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
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)
}
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
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;
}