2017-06-10 77 views
0

我有下面的代碼,以獲取有關TCP端口的信息:轉換[UINT8]數組來xinpgen結構

var length = 0 
if (sysctlbyname("net.inet.tcp.pcblist", nil, &length, nil, 0) < 0) 
{ 
    perror("sysctlbyname") 
} 
else 
{ 
    var buffer: [UInt8] = [UInt8](repeating: 0, count: Int(length)) 
    sysctlbyname("net.inet.tcp.pcblist", &buffer, &length, nil, 0) 
} 

我現在想的緩衝區轉換成一些更「有用」。我讀過返回值是一個名爲「xinpgen」的結構。 如何將緩衝區轉換爲該結構?

我嘗試下面的代碼直接寫結果到結構體變量:

var length = 0 
if (sysctlbyname("net.inet.tcp.pcblist", nil, &length, nil, 0) < 0) 
{ 
    perror("sysctlbyname") 
} 
else 
{ 
    var input = xinpgen() 
    sysctlbyname("net.inet.tcp.pcblist", &input, &length, nil, 0) 
} 

本身並沒有失敗,調用似乎是成功的。該變量包含一些不爲零的數據。但不久後在通話結束後,程序繼續執行,應用程序崩潰:

error: memory read failed for 0x0 

如何使用緩衝區來填充結構體變量?爲什麼第二次通話失敗?

+0

這顯然沒有C代碼。 – Olaf

+0

這是Swift,但我想將「Swift對象」轉換爲C結構。 –

+0

「我想將」Swift對象「轉換爲C結構」 - 不完全。你想將一個swift對象轉換成符合你的平臺的C ** ABI **的內存塊。這與C語言無關,而是一個純粹的快速問題。 – Olaf

回答

1

sysctlbyname("net.inet.tcp.pcblist", ...) 返回的數據不是單個的xinpgen結構,而是一個「打包列表」 結構。

您的代碼將更多的字節寫入變量的內存地址比其大小,行爲是未定義的,並且很有可能會崩潰。

我不知道是否記錄了返回數據的結構,但 ​​的源代碼顯示瞭如何解析它。 顯然,緩衝區以struct xinpgen開頭,後面的 由可變數字struct xtcpcb開始,每個元素都有一個長度字段,其中包含到下一個結構的偏移量。

這是我試圖從上述源 文件中的C代碼轉換爲斯威夫特:

var length = 0 
if (sysctlbyname("net.inet.tcp.pcblist", nil, &length, nil, 0) < 0) { 
    fatalError("sysctlbyname") 
} 

var buffer = [UInt8](repeating: 0, count: Int(length)) 
sysctlbyname("net.inet.tcp.pcblist", &buffer, &length, nil, 0) 

buffer.withUnsafeBytes { bufPtr in 

    // Pointer to first xinpgen structure: 
    var p = bufPtr.baseAddress! 
    var xig = p.bindMemory(to: xinpgen.self, capacity: 1) 

    // Skip first xinpgen structure: 
    p += Int(xig.pointee.xig_len) 
    xig = p.bindMemory(to: xinpgen.self, capacity: 1) 

    while Int(xig.pointee.xig_len) > MemoryLayout<xinpgen>.size { 
     // Cast xig to xtcpcb pointer and derefernce: 
     let tcpcb = xig.withMemoryRebound(to: xtcpcb.self, capacity: 1) { 
      $0.pointee 
     } 
     print(tcpcb) 

     // Advance pointer to next structure 
     p += Int(xig.pointee.xig_len) 
     xig = p.bindMemory(to: xinpgen.self, capacity: 1) 
    } 
} 
+0

謝謝,我得到它的工作。 netstat打印url(stackoverflow.com或localhost)而不是IP地址。有什麼方法可以在Swift中獲取這些信息嗎?我有IP地址,並希望URL。 –

+1

@SaschaSimon:'getnameinfo()'可用於獲取IP地址的主機名。 –

+1

@SaschaSimon:這可能有助於https://stackoverflow.com/questions/41494466/getting-an-ip-address-and-port-number-from-a-sockaddr-in-struct-in-swift(但沒有NI_NUMERIC ...選項) –