问题
Just trying Bonjour in swift 3
Here is my code , I can receive the delegate
func netServiceDidResolveAddress(_ sender: NetService) {
print("netServiceDidResolveAddress service name \(sender.name) of type \(sender.type)," +
"port \(sender.port), addresses \(sender.addresses)")
}
And here is my result
netServiceDidResolveAddress service name Webber's Mac mini of type _myapp._tcp.,port 5678, addresses Optional([<1002162e c0a80205 00000000 00000000>, <1c1e162e 00000000 fe800000 00000000 00bce7ad 24b4b7e8 08000000>])
c0a80205 is the IP I looking for => 192.168.2.5
And the address is [Data] , Apple says
The addresses of the service. This is an NSArray of NSData instances, each of which contains a single struct sockaddr suitable for use with connect(2). In the event that no addresses are resolved for the service or the service has not yet been resolved, an empty NSArray is returned.
I still confuse why Data can't use .btyes ? As Apple says "This is an NSArray of NSData instances" But I can't use it like NSData
And how to resolve the address as readable IP string ?
I try this before , but do not get the result as I except ...
let thedata = NSData(bytes: sender.addresses, length: (sender.addresses?.count)!)
var storage = sockaddr_storage()
thedata.getBytes(&storage, length: sizeof(sockaddr_storage))
if Int32(storage.ss_family) == AF_INET {
let addr4 = withUnsafePointer(&storage) {UnsafePointer<sockaddr_in>($0).pointee }
print(inet_ntoa(addr4.sin_addr));
}
Any suggestion will be help , Thanks
回答1:
Here's how I did it in Swift 3.
func netServiceDidResolveAddress(_ sender: NetService) {
var hostname = [CChar](repeating: 0, count: Int(NI_MAXHOST))
guard let data = sender.addresses?.first else { return }
data.withUnsafeBytes { (pointer:UnsafePointer<sockaddr>) -> Void in
guard getnameinfo(pointer, socklen_t(data.count), &hostname, socklen_t(hostname.count), nil, 0, NI_NUMERICHOST) == 0 else {
return
}
}
let ipAddress = String(cString:hostname)
print(ipAddress)
}
回答2:
I can't make it work with Data
, but using NSData
, I would use this:
extension NSData {
func castToCPointer<T>() -> T {
let mem = UnsafeMutablePointer<T>.allocate(capacity: MemoryLayout<T.Type>.size)
self.getBytes(mem, length: MemoryLayout<T.Type>.size)
return mem.move()
}
}
So we have netServiceDidResolveAddress
:
func netServiceDidResolveAddress(_ sender: NetService) {
if let addresses = sender.addresses, addresses.count > 0 {
for address in addresses {
let data = address as NSData
let inetAddress: sockaddr_in = data.castToCPointer()
if inetAddress.sin_family == __uint8_t(AF_INET) {
if let ip = String(cString: inet_ntoa(inetAddress.sin_addr), encoding: .ascii) {
// IPv4
print(ip)
}
} else if inetAddress.sin_family == __uint8_t(AF_INET6) {
let inetAddress6: sockaddr_in6 = data.castToCPointer()
let ipStringBuffer = UnsafeMutablePointer<Int8>.allocate(capacity: Int(INET6_ADDRSTRLEN))
var addr = inetAddress6.sin6_addr
if let ipString = inet_ntop(Int32(inetAddress6.sin6_family), &addr, ipStringBuffer, __uint32_t(INET6_ADDRSTRLEN)) {
if let ip = String(cString: ipString, encoding: .ascii) {
// IPv6
print(ip)
}
}
ipStringBuffer.deallocate(capacity: Int(INET6_ADDRSTRLEN))
}
}
}
}
I am having the following result (storing ips in array before display):
["172.16.10.120", "172.16.8.251", "::", "::82c9:d9a5:2eed:1c87"]
Code inspired by https://gist.github.com/agrippa1994/d8c66a2ded74fb2dd801 written in Swift 2.3 and adapted for Swift 3.0
回答3:
OK ... this is not a smart answer , at least I can get the readable IP
Just use this func to get IP string
let bonjourDevices = [NetService]()
let bonjourDevice = bonjourDevices[0]
let host = self.getIPV4StringfromAddress(address:bonjourDevice.addresses!)
func getIPV4StringfromAddress(address: [Data] , port : Int ) -> String{
let data = address.first! as NSData;
var ip1 = UInt8(0)
data.getBytes(&ip1, range: NSMakeRange(4, 1))
var ip2 = UInt8(0)
data.getBytes(&ip2, range: NSMakeRange(5, 1))
var ip3 = UInt8(0)
data.getBytes(&ip3, range: NSMakeRange(6, 1))
var ip4 = UInt8(0)
data.getBytes(&ip4, range: NSMakeRange(7, 1))
let ipStr = String(format: "%d.%d.%d.%d:%d",ip1,ip2,ip3,ip4,port);
return ipStr;
}
回答4:
Edited Phil Coles answer for Swift 5.0 warning free solution:
func netServiceDidResolveAddress(_ sender: NetService) {
var hostname = [CChar](repeating: 0, count: Int(NI_MAXHOST))
guard let data = sender.addresses?.first else { return }
data.withUnsafeBytes { ptr in
guard let sockaddr_ptr = ptr.baseAddress?.assumingMemoryBound(to: sockaddr.self) else {
// handle error
return
}
var sockaddr = sockaddr_ptr.pointee
guard getnameinfo(sockaddr_ptr, socklen_t(sockaddr.sa_len), &hostname, socklen_t(hostname.count), nil, 0, NI_NUMERICHOST) == 0 else {
return
}
}
let ipAddress = String(cString:hostname)
print(ipAddress)
}
来源:https://stackoverflow.com/questions/38197198/swift-3-how-to-resolve-netservice-ip