8

目前我正在使用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)
4

1 回答 1

4

这个有可能。

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

此外,服务与特定 IP 地址甚至主机名无关。[…] 如果客户端存储主机名(在大多数情况下,他们现在这样做),如果服务移动到不同的主机,他们将无法连接。

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

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

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

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 停止使用该端口)并将其用于您自己的目的。

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

在这个 Apple Developer Forum 主题中,Apple官方代表提供了更多背景信息。

于 2021-08-10T07:10:42.537 回答