我在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)。
这是在调试期间,没有我所知道的优化。如果我在模拟器或真实设备上运行它并不重要。
有人可以解释为什么会这样吗?
答案 0 :(得分:1)
问题是getnameinfo
期望指针可以是sockaddr_in
或sockaddr_in6
。函数的定义有点令人困惑,因为它需要一个sockaddr
指针。
因为我正在使用扩展来提取IP地址,所以正在复制内存内容。这不是IPv4的问题,因为sockaddr_in
的大小与sockaddr
的大小相同。但是对于IPv6,sockaddr_in6
大于sockaddr
结构,并且一些相关信息被截断。
我的命令顺序可能决定了sockaddr
地址后面的内存中存储的内容。有时它看起来像一个合适的IPv6地址,但实际上是不正确的。
我已将扩展程序移至网络接口ifaddrs
:
extension ifaddrs {
/// Returns the IP address.
var ipAddress: String? {
var buffer = [CChar](repeating: 0, count: Int(NI_MAXHOST))
let address = ifa_addr.pointee
let result = getnameinfo(ifa_addr, socklen_t(address.sa_len), &buffer, socklen_t(buffer.count), nil, socklen_t(0), NI_NUMERICHOST)
return result == 0 ? String(cString: buffer) : nil
}
}
感谢@MartinR找到问题的原因!