【发布时间】:2017-11-12 16:03:05
【问题描述】:
我在sockaddr 上有以下分机:
extension sockaddr {
/// Indicates if this is an IPv4 address.
var isIPv4: Bool {
return sa_family == UInt8(AF_INET)
}
/// Indicates if this is an IPv6 address.
var isIPv6: Bool {
return sa_family == UInt8(AF_INET6)
}
/// Returns the address in string notation.
var address: String? {
var result: String = ""
var me = self
var hostname = [CChar](repeating: 0, count: Int(NI_MAXHOST))
if getnameinfo(&me, socklen_t(me.sa_len), &hostname, socklen_t(hostname.count), nil, socklen_t(0), NI_NUMERICHOST) == 0 {
result = String(cString: hostname)
}
return result
}
}
在我的代码的另一部分,我调用getifaddrs 来获取当前设备的接口地址。上面的代码在 IPv4 上运行良好,但在 IPv6 上有些不可靠。
我得到如下结果:192.168.1.10 和 fe80::e0fa:1204:100:0
当我将var result: String = "" 更改为var result: String? = nil 时。 IPv6地址突然变成fe80::,剩下的就被切断了。
更奇怪的是,当我像这样切换 var result 和 var me = self 行时:
extension sockaddr {
/// Indicates if this is an IPv4 address.
var isIPv4: Bool {
return sa_family == UInt8(AF_INET)
}
/// Indicates if this is an IPv6 address.
var isIPv6: Bool {
return sa_family == UInt8(AF_INET6)
}
/// Returns the address in string notation.
var address: String? {
var me = self
var result: String = ""
var hostname = [CChar](repeating: 0, count: Int(NI_MAXHOST))
if getnameinfo(&me, socklen_t(me.sa_len), &hostname, socklen_t(hostname.count), nil, socklen_t(0), NI_NUMERICHOST) == 0 {
result = String(cString: hostname)
}
return result
}
}
那么该功能将仅适用于 IPv4 地址。 getnameinfo 将返回 4 (FAIL)。
这是在调试过程中,据我所知没有任何优化。在模拟器或真机上运行都没关系。
有人能解释一下为什么会这样吗?
【问题讨论】:
-
正如我在回答您之前的问题stackoverflow.com/questions/44426911/… 时所说的:
struct sockaddr不能 持有 IPv6 地址。因此,如果您得到正确的结果,那纯属偶然。 – 你如何使用getifaddrs()的扩展方法?你看过stackoverflow.com/a/25627545/1187415,哪个(现在)可以正常工作了吗? -
是的,我确实看过。行
let addr = ptr.pointee.ifa_addr.pointee产生sockaddr。如果您检查定义,您将看到以下内容:public var ifa_addr: UnsafeMutablePointer<sockaddr>!。基本上我所做的只是将之后的部分移动到sockaddr上的扩展名。 -
同样
getnameinfo的定义以public func getnameinfo(_: UnsafePointer<sockaddr>!,开头。而getnameinfo可以同时解析 IPv4 和 IPv6 地址。 -
getnameinfo()将 指针 指向sockaddr,而不是sockaddr本身。ptr.pointee.ifa_addr是从getifaddrs()获得的指针,可以指向 IPv4 或 IPv6 地址。 – 你是对的:let addr = ptr.pointee.ifa_addr.pointee只复制“common”部分,这是为了方便,只用于访问addr.sa_family。但是 pointer 被传递给getnameinfo()(实际上我最初是错的,如果您查看答案的最后编辑) -
好的,但是那样做和通过扩展做有什么区别呢?我将
&me传递给getnameinfo,这是一个指向sockaddr的指针,对吗?
标签: swift sockaddr getnameinfo