我正在尝试快速进行简单的DNS查找。到目前为止,这是我拥有的代码:
let hostRef = CFHostCreateWithName(kCFAllocatorDefault, "google.com").takeRetainedValue()
var resolved = CFHostStartInfoResolution(hostRef, CFHostInfoType.Addresses, nil)
let addresses = CFHostGetAddressing(hostRef, &resolved).takeRetainedValue() as NSArray
此时,“地址” NSArray中的每个元素都是一个CFDataRef对象,该对象包装了一个sockaddr结构。
由于CFDataRef可以免费连接到NSData,因此可以像这样循环遍历它们:
for address: AnyObject in addresses {
println(address) // address is of type NSData.
}
到目前为止,一切都很好(我认为)。当我在单元测试中运行时,这会打印出有效的外观数据。这是我被卡住的地方。为了我的一生,我不知道如何将NSData对象中的字节转换为sockaddr结构。
如何将COpaquePointer类型的address.bytes转换为ac struct?任何帮助表示赞赏。我把头撞在墙上,试图解决这个问题。
有关使用的更简单解决方案getnameinfo
,请参见Martin的回答:如何在Swift中从DNS查询中获取真实IP地址?
已针对Swift 5 / IPv6更新:
CFHostGetAddressing
可以将返回的对象作为数据桥接到Swift
,并使用和强制转换为in_addr
/
。in6_addr
withUnsafeBytes
assumingMemoryBound(to:)
这是一个完整的示例,用于inet_ntop
将IPv4 / IPv6地址转换为字符串:
import CFNetwork
import Foundation
protocol NetworkAddress {
static var family: Int32 { get }
static var maxStringLength: Int32 { get }
}
extension in_addr: NetworkAddress {
static let family = AF_INET
static let maxStringLength = INET_ADDRSTRLEN
}
extension in6_addr: NetworkAddress {
static let family = AF_INET6
static let maxStringLength = INET6_ADDRSTRLEN
}
extension String {
init<A: NetworkAddress>(address: A) {
// allocate a temporary buffer large enough to hold the string
var buf = ContiguousArray<Int8>(repeating: 0, count: Int(A.maxStringLength))
self = withUnsafePointer(to: address) { rawAddr in
buf.withUnsafeMutableBufferPointer {
String(cString: inet_ntop(A.family, rawAddr, $0.baseAddress, UInt32($0.count)))
}
}
}
}
func addressToString(data: Data) -> String? {
return data.withUnsafeBytes {
let family = $0.baseAddress!.assumingMemoryBound(to: sockaddr_storage.self).pointee.ss_family
// family determines which address type to cast to (IPv4 vs IPv6)
if family == numericCast(AF_INET) {
return String(address: $0.baseAddress!.assumingMemoryBound(to: sockaddr_in.self).pointee.sin_addr)
} else if family == numericCast(AF_INET6) {
return String(address: $0.baseAddress!.assumingMemoryBound(to: sockaddr_in6.self).pointee.sin6_addr)
}
return nil
}
}
let host = CFHostCreateWithName(kCFAllocatorDefault, "google.com" as CFString).takeRetainedValue()
var resolved = DarwinBoolean(CFHostStartInfoResolution(host, .addresses, nil))
let addresses = CFHostGetAddressing(host, &resolved)?.takeUnretainedValue() as! [Data]?
print(addresses?.compactMap(addressToString))
您可以使用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))
}
问题内容: 这是我的职责 首先将正确的哈希值打印到控制台,但在下一行程序崩溃。你能帮助我吗? 问题答案: 返回如果数据不表示一个有效的UTF-8序列(这是非常可能的)。然后以下崩溃。 任意二进制数据的可能字符串表示形式可能是十六进制字符串或Base-64编码的字符串。 甲 Base64编码串 可以简单地获得与 据我所知,没有内置的方法可以将二进制数据转换为 十六进制字符串 。在Swift中可能的实
问题内容: 我在Swift 中将元素转换为,然后将变量转换回时遇到了问题。 首先,我想提取以下JSON数据的元素: 放入NSData 变量,但似乎无法做到这一点。我用来解析如下: 但这给了我一个ScalarNumber数组,我不知道如何存储到一个对象中。 其次,我想从同一个对象生成回来: 但是NSData 对象不会转换为[-67,51,-38,61,-72,102,48],它只是使JSON字符串无
问题内容: 我有此表达式返回一个: 我希望能够在此if语句中使用数字: 问题是控制台给了我这个 问题是无法与进行比较。我想投到一个。我努力了: 这些都导致 如何转换值或在if语句中使用它? 问题答案: 做两件事,一是消除当前方法的负面结果,二是应根据结果正确创建一个Int。
问题内容: 我有那个代码 有时,强制转换为无效。当我看到。为什么会这样呢?我使用来自GitHub的SwiftSocket库。对不起我的英语不好。 当我的服务器发送大字符串时会发生这种情况。例如- 如果我收到一个消息对象(我的班级)-一切都会正常。但是,如果我收到4,5,6,…消息对象(我的班级),这有时会起作用。MAGIC :( 新版本的代码 问题答案: 注意:我不会讲Swift。以下代码可能无法
问题内容: 怎么转换成?如果应该这样做 那怎么算呢? 以及如何转换为? 问题答案: 缓冲区长度为frameCapacity * bytesPerFrame。以下是可以在NSData和AVAudioPCMBuffer之间进行转换的函数。
问题内容: 我最近一直在编写与iPhone交互的Web应用程序。iPhone iphone实际上将以plist的形式将信息发送到服务器。因此,看到类似…的情况并不少见。 现在,我知道此数据已以某种方式进行了哈希/加密。当我使用编辑器(“属性列表编辑器”)打开plist时,它向我展示了一种更加“易于阅读”的格式。例如,上面的数据将被转换为… 知道转换的方法是什么吗?主要是我希望将其放入Java St