在swift中将NSData转换为sockaddr结构体
我正在试图做一个简单的DNS查询迅速。 到目前为止,这里是我有的代码:
let hostRef = CFHostCreateWithName(kCFAllocatorDefault, "google.com").takeRetainedValue() var resolved = CFHostStartInfoResolution(hostRef, CFHostInfoType.Addresses, nil) let addresses = CFHostGetAddressing(hostRef, &resolved).takeRetainedValue() as NSArray
此时,“地址”NSArray中的每个元素都是包装sockaddr结构体的CFDataRef对象。
由于CFDataRef可以免费桥接到NSData,我可以像这样循环他们:
for address: AnyObject in addresses { println(address) // address is of type NSData. }
到目前为止好(我认为)。 当我在unit testing中运行它时打印出有效的数据。 这里是我卡住的地方。 对于我来说,我不知道如何将NSData对象中的字节转换为sockaddr结构体。
我怎样才能将address.bytestypes的COpaquePointer?转换成ac结构? 任何帮助赞赏。 我正在试图弄清楚这一切,正在撞墙。
您可以使用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)) } }
更新6/3/2015:现在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:将未初始化的C结构传递给导入的C函数