我试图在swift中进行简单的DNS查找。到目前为止,这是我的代码:
let hostRef = CFHostCreateWithName(kCFAllocatorDefault, "google.com").takeRetainedValue()
var resolved = CFHostStartInfoResolution(hostRef, CFHostInfoType.Addresses, nil)
let addresses = CFHostGetAddressing(hostRef, &resolved).takeRetainedValue() as NSArray
此时,"中的每个元素都解决了#34; NSArray是一个包装sockaddr结构的CFDataRef对象。
由于CFDataRef可以免费桥接到NSData,我可以像这样循环遍历它们:
for address: AnyObject in addresses {
println(address) // address is of type NSData.
}
到目前为止一切顺利(我认为)。当我在单元测试中运行时,这会打印出有效的数据。这是我陷入困境的地方。对于我的生活,我无法弄清楚如何将NSData对象中的字节转换为sockaddr结构。
如何将address.bytes(COpaquePointer?类型)转换为c结构?任何帮助赞赏。我试图弄明白这一点,把头撞在墙上。
答案 0 :(得分:10)
您可以使用NSData方法getBytes(_, length:)
方法,并使用前缀&
运算符将sockaddr结构传递给inout参数:
var data: NSData ...
var address: sockaddr ...
data.getBytes(&address, length: MemoryLayout<sockaddr>.size)
更新了Swift 3:
let host = CFHostCreateWithName(kCFAllocatorDefault, "google.com" as CFString).takeRetainedValue()
var resolved = DarwinBoolean(CFHostStartInfoResolution(host, .addresses, nil))
let addresses = CFHostGetAddressing(host, &resolved)?.takeUnretainedValue() as! [NSData]?
if let data = addresses?.first {
var storage = sockaddr_storage()
data.getBytes(&storage, length: MemoryLayout<sockaddr_storage>.size)
if Int32(storage.ss_family) == AF_INET {
let addr4 = withUnsafePointer(to: &storage) {
$0.withMemoryRebound(to: sockaddr_in.self, capacity: 1) {
$0.pointee
}
}
// prints 74.125.239.132
print(String(cString: inet_ntoa(addr4.sin_addr), encoding: .ascii))
}
}
2015年6月3日更新:
现在C结构可以很容易地进行零初始化,这变得更加简单:
let host = CFHostCreateWithName(kCFAllocatorDefault, "google.com").takeRetainedValue()
var resolved = CFHostStartInfoResolution(host, .Addresses, nil)
let addresses = CFHostGetAddressing(host, &resolved)?.takeUnretainedValue() as! [NSData]?
if let data = addresses?.first {
var storage = sockaddr_storage()
data.getBytes(&storage, length: sizeof(sockaddr_storage))
if Int32(storage.ss_family) == AF_INET {
let addr4 = withUnsafePointer(&storage) { UnsafePointer<sockaddr_in>($0).memory }
// prints 74.125.239.132
println(String(CString: inet_ntoa(addr4.sin_addr), encoding: NSASCIIStringEncoding))
}
}
击> <击> 撞击>
不幸的是,这需要首先初始化 sockaddr
。为避免这种情况,您可以执行以下操作:
func makeWithUnsafePointer<T>(body: UnsafePointer<T> -> ()) -> T {
let ptr = UnsafePointer<T>.alloc(sizeof(T))
body(ptr)
return ptr.move()
}
let addr: sockaddr = makeWithUnsafePointer {
data.getBytes($0 as UnsafePointer<sockaddr>, length: sizeof(sockaddr))
}
或者这个:
func makeWithUninitialized<T>(body: inout T -> ()) -> T {
let ptr = UnsafePointer<T>.alloc(sizeof(T))
body(&ptr.memory)
return ptr.move()
}
let addr = makeWithUninitialized { (inout addr: sockaddr) in
data.getBytes(&addr, length: sizeof(sockaddr))
}
有关更多讨论,请参阅Swift: Pass Uninitialized C Structure to Imported C function
击>