如何从 NWEndpoint.service 枚举案例中解析地址和端口信息(如果可能)

How to resolve addresses and port information from an NWEndpoint.service enum case (if possible)

目前我正在使用NetServiceBrowser查找Bonjour服务并解析相应的地址和端口。

为了简化我的代码,我偶然发现了 NWBrowser,它似乎提供了一个非常简单的界面来处理 Bonjour 发现。

但是,browseResultsChangedHandler 发回结果和更改,其中包含枚举案例 service 的端点。我试图从结果中获取地址和端口信息,但似乎 NWEndpoint 必须是枚举类型 .hostPort.

理想情况下,我会使用端点连接到使用 NWConnection 的服务器,但是,我使用的是另一个不直接处理 NWEndpoint 的库。

是否有(简单的)方法从 NWEndpoint.service 结果中获取地址和端口信息?

import Foundation
import Network

let browser = NWBrowser(for: .bonjour(type: "_http._tcp", domain: ""), using: NWParameters())

browser.browseResultsChangedHandler = { (results, changes) in
    print("Results:")

    for result in results
    {
        if case .service(let service) = result.endpoint
        {
            debugPrint(service)
        }
        else
        {
            assert(false, "This nevers gets executed")
        }
    }

    print("Changes:")

    for change in changes
    {
        if case .added(let added) = change
        {
            if case .service(let service) = added.endpoint
            {
                debugPrint(service)
            }
            else
            {
                assert(false, "This nevers gets executed")
            }
        }
    }
}

browser.start(queue: DispatchQueue.main)

sleep(3)

这是可能的。

首先,您应该尝试获取服务的主机和端口,直到用户实际选择连接到它 - 在您的大多数应用程序中,您应该只存储一个对服务对象的引用,因为 Bonjour 允许更改服务的主机和端口。来自 Bonjour Concepts:

Additionally, services are not tied to specific IP addresses or even host names. […] If clients store the host name (as in most cases they now do), they will not be able to connect if the service moves to a different host.

Bonjour takes the service-oriented view. Queries are made according to the type of service needed, not the hosts providing them. Applications store service instance names, not addresses, so if the IP address, port number, or even host name has changed, the application can still connect. By concentrating on services rather than devices, the user’s browsing experience is made more useful and trouble-free.

这可以减少您网络中的 DNS 噪音,并且是 Bonjour 设计的核心。这意味着我接下来的所有建议都应该 而不是 发生在你的 browseResultsChangedHandler.

官方推荐的使用 NWBrowser 的方法似乎是打开一个 NWConnection 服务并使用它,而不是提取地址和端口并手动连接。您可以打开连接,网络框架将处理实际的解析 host/port 并连接到服务。

let connection = NWConnection(to: service.endpoint, using: .tcp)

connection.stateUpdateHandler = { state in
    switch state {
    case .ready:
        if let innerEndpoint = connection.currentPath?.remoteEndpoint,
           case .hostPort(let host, let port) = innerEndpoint {
            print("Connected to", "\(host):\(port)") // Here, I have the host/port information
        }
    default:
        break
    }
}
connection.start(queue: .global())

如果您不能使用此网络框架连接,我想您可以关闭连接(可能需要等待 TCP 停止使用该端口)并将其用于您自己的目的。

您还可以使用已弃用的 NetService api to resolve a service (although I haven't personally gotten this to work with a manually constructed instance) or DNSServiceResolve

this Apple Developer Forum thread 中的 Apple 官方代表提供了更多背景信息。