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

Ruu*_*ema 7 macos bonjour dns-sd swift network-framework

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

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

但是,browseResultsChangedHandler返回包含 enum case 端点的结果和更改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)
Run Code Online (Sandbox Code Playgroud)

Cam*_*tle 10

这个有可能。

\n

首先,在用户实际选择连接到服务之前,不应尝试获取服务的主机和端口 - 在大多数应用程序中,您应该只存储对服务对象的引用,因为 Bonjour 允许服务\的主机和端口要更改。来自卓悦概念

\n
\n

此外,服务不依赖于特定的 IP 地址甚至主机名。[\xe2\x80\xa6] 如果客户端存储主机名(就像现在大多数情况下一样),那么如果服务移动到其他主机,它们将无法连接。

\n

Bonjour 采取以服务为导向的观点。查询是根据所需服务的类型进行的,而不是根据提供服务的主机进行的。应用程序存储服务实例名称,而不是地址,因此如果 IP 地址、端口号甚至主机名发生更改,应用程序仍然可以连接。通过专注于服务而不是设备,用户\xe2\x80\x99的浏览体验变得更加有用且无故障。

\n
\n

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

\n

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

\n
let connection = NWConnection(to: service.endpoint, using: .tcp)\n\nconnection.stateUpdateHandler = { state in\n    switch state {\n    case .ready:\n        if let innerEndpoint = connection.currentPath?.remoteEndpoint,\n           case .hostPort(let host, let port) = innerEndpoint {\n            print("Connected to", "\\(host):\\(port)") // Here, I have the host/port information\n        }\n    default:\n        break\n    }\n}\nconnection.start(queue: .global())\n
Run Code Online (Sandbox Code Playgroud)\n

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

\n

您还可以使用已弃用的NetServiceapi 来解析服务(尽管我个人还没有让它与手动构建的实例一起使用)或DNSServiceResolve.

\n

在这个 Apple 开发者论坛帖子中,Apple 官方代表提供了更多背景信息。

\n