【问题标题】:Swift 3 how to resolve NetService IP?Swift 3 如何解析 NetService IP?
【发布时间】:2016-07-05 07:05:43
【问题描述】:

只是在 swift 3 中尝试 Bonjour

这是我的代码,我可以接收委托

func netServiceDidResolveAddress(_ sender: NetService) {
 print("netServiceDidResolveAddress service name \(sender.name) of type \(sender.type)," +
                "port \(sender.port), addresses \(sender.addresses)")
}

这是我的结果

netServiceDidResolveAddress 服务名称 Webber 的 Mac mini 类型 _myapp._tcp.,端口 5678,地址可选([,])

c0a80205 是我要找的 IP => 192.168.2.5

地址是 [Data] ,Apple 说

服务的地址。这是 NSData 实例的 NSArray, 每个都包含一个适合使用的 struct sockaddr 连接(2)。如果没有为 服务或者服务还没有被解析,一个空的 NSArray 是 返回。

我仍然很困惑为什么 Data 不能使用 .btyes ? 正如苹果所说“这是一个 NSData 实例的 NSArray” 但是我不能像 NSData 那样使用它

以及如何将地址解析为可读的IP字符串?

我之前试过这个,但没有像我一样得到结果...

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

任何建议都会有所帮助,谢谢

【问题讨论】:

    标签: ios ipv4 swift3 nsnetservice nsnetservicebrowser


    【解决方案1】:

    这是我在 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)
    }
    

    斯威夫特 5

    var hostname = [CChar](repeating: 0, count: Int(NI_MAXHOST))
    data.withUnsafeBytes { (pointer: UnsafeRawBufferPointer) -> Void in
            let sockaddrPtr = pointer.bindMemory(to: sockaddr.self)
            guard let unsafePtr = sockaddrPtr.baseAddress else { return }
            guard getnameinfo(unsafePtr, socklen_t(data.count), &hostname, socklen_t(hostname.count), nil, 0, NI_NUMERICHOST) == 0 else {
                return
            }
        }
    let ipAddress = String(cString:hostname)
    print(ipAddress)
    

    【讨论】:

    • Phil,使用 Swift 5 我收到警告:'withUnsafeBytes' 已弃用:请改用 withUnsafeBytes&lt;R&gt;(_: (UnsafeRawBufferPointer) throws -&gt; R) rethrows -&gt; R。你能告诉我如何解决这个问题吗,Apple 的文档太让我头疼了。
    • 使用建议的 withUnsafeBytes 方法并使用 baseAddress.sumptionMemoryBound(to:) 进行转换,请参阅下面的答案。
    【解决方案2】:

    为 Swift 5.0 无警告解决方案编辑了 Phil Coles 的答案:

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

    【讨论】:

      【解决方案3】:

      好的...这不是一个聪明的答案,至少我可以获得可读的IP

      使用这个函数来获取IP字符串

      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】:

        我无法使用Data,但使用NSData,我会使用这个:

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

        所以我们有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))
                    }
                }
            }
        }
        

        我得到以下结果(在显示之前将 ips 存储在数组中):

        ["172.16.10.120", "172.16.8.251", "::", "::82c9:d9a5:2eed:1c87"]
        

        https://gist.github.com/agrippa1994/d8c66a2ded74fb2dd801 启发的代码用 Swift 2.3 编写并适用于 Swift 3.0

        【讨论】:

        • ipStringBuffer.deallocate(capacity: Int(INET6_ADDRSTRLEN)) 已折旧。请改用 ipStringBuffer.deallocate()。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-12-01
        • 1970-01-01
        相关资源
        最近更新 更多