将 [UInt8] 数组转换为 xinpgen 结构
Convert [UInt8] Array to xinpgen struct
我有以下代码来获取有关 tcp 端口的信息:
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)
}
我现在想将缓冲区转换成更多内容 "useful"。我读到 return 值是一个名为 "xinpgen" 的结构。
如何将缓冲区转换为该结构?
我试过下面的代码直接将结果写入struct变量:
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
如何使用缓冲区填充结构变量?为什么第二次调用失败?
sysctlbyname("net.inet.tcp.pcblist", ...)
返回的数据
不是单个 xinpgen
结构,而是 "packed list" 个
结构。
您的代码将更多字节写入 input
的内存地址
比它的大小可变,行为是未定义的并且崩溃非常
有可能。
我不知道是否记录了返回数据的结构,但是
inet.c 的源代码显示了如何解析它。
显然缓冲区以 struct xinpgen
开头,然后是
由可变数量的 struct xtcpcb
,每个元素都有
一个长度字段,其中包含到下一个结构的偏移量。
这是我尝试翻译上述源代码的C代码
文件到 Swift:
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) {
[=10=].pointee
}
print(tcpcb)
// Advance pointer to next structure
p += Int(xig.pointee.xig_len)
xig = p.bindMemory(to: xinpgen.self, capacity: 1)
}
}
我有以下代码来获取有关 tcp 端口的信息:
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)
}
我现在想将缓冲区转换成更多内容 "useful"。我读到 return 值是一个名为 "xinpgen" 的结构。 如何将缓冲区转换为该结构?
我试过下面的代码直接将结果写入struct变量:
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
如何使用缓冲区填充结构变量?为什么第二次调用失败?
sysctlbyname("net.inet.tcp.pcblist", ...)
返回的数据
不是单个 xinpgen
结构,而是 "packed list" 个
结构。
您的代码将更多字节写入 input
的内存地址
比它的大小可变,行为是未定义的并且崩溃非常
有可能。
我不知道是否记录了返回数据的结构,但是
inet.c 的源代码显示了如何解析它。
显然缓冲区以 struct xinpgen
开头,然后是
由可变数量的 struct xtcpcb
,每个元素都有
一个长度字段,其中包含到下一个结构的偏移量。
这是我尝试翻译上述源代码的C代码 文件到 Swift:
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) {
[=10=].pointee
}
print(tcpcb)
// Advance pointer to next structure
p += Int(xig.pointee.xig_len)
xig = p.bindMemory(to: xinpgen.self, capacity: 1)
}
}