【问题标题】:Bonjour: Search for a service by nameBonjour:按名称搜索服务
【发布时间】:2017-09-01 12:03:09
【问题描述】:

我有一个应用程序需要搜索和解析 Bonjour 广告服务,该服务的名称是预先知道的。我发现的大多数与服务发现相关的 Bonjour 示例的结构或多或少是这样的:

  1. 调用browse 以检测给定类型的所有服务(例如,这可能是_http._tcp
  2. 对于找到的每个服务,都会调用serviceFound。此处报告服务名称
  3. 在找到的每个服务上调用 resolve
  4. 对于每个解析的服务,都会调用serviceResolved

Bonjour 是否可以跳过“发现”阶段,因为我事先知道要解析的服务的名称?我可以只检测并解析具有已知名称的服务吗?

【问题讨论】:

    标签: network-programming bonjour zeroconf


    【解决方案1】:

    1- 答案

    是的,如果您已经知道服务的名称,则可以从第 3 步开始。这是因为此步骤是通过 DNS 查找具有发送到众所周知的多播地址的服务名称的 SRV 记录来执行的。因此,进行此调用不需要先前的信息,并且 mDNS 响应者必须是无状态的,因为底层 DNS 协议是无状态的(每个响应都绑定到一个唯一的请求 - 在多个请求之间不维护任何状态)。

    2-示例

    这是我刚刚用 Swift 编写的一个示例,它通过了在我的 iPad 上运行的测试,可以找到在我的 Mac Mini 上运行的服务。 所以,我们假设域名为local,服务类型为_http._tcp,服务名称为myservice,运行在Mac-mini-de-Alexandre.local主机上,监听TCP端口8080。

    为了跟踪有关服务的信息,例如它的主机名和 TCP 端口,我们定义了一个实现 NetServiceDelegate 协议的类:

    class MyNetServiceDelegate : NSObject, NetServiceDelegate {
         public func netServiceDidResolveAddress(_ sender: NetService) {
            print(sender.hostName!, sender.port)
        }
    }
    

    这个新类将用于实例化 NetService 实例的委托。

    因此,我们创建一个与我们已经知道的服务相对应的 NetService 实例,我们将其长期存储在某个主类的静态常量属性中:

    static let ns = NetService(domain: "local.", type: "_http._tcp.", name: "myservice")
    

    它是长期存储的,因为在我们找到我们的服务之前不能释放它。

    请注意,NetService 类中的委托属性声明为 unowned(unsafe)。因此,我们还需要创建对委托实例的引用:

    static let ns_deleg = MyNetServiceDelegate()
    

    当我们要解析服务时,可以这样写:

    ns.delegate = ns_deleg
    ns.resolve(withTimeout: TimeInterval(10))
    

    如果找到服务,稍后将调用委托实例(resolve() 是非阻塞方法),在这种情况下,它将打印主机名和端口。

    这是我在 Xcode 输出窗口中得到的输出:

    Mac-mini-de-Alexandre.local. 8080
    

    最后,请注意,由于无主引用,编写以下代码将是错误的(委托实例将很快被释放):

    // bad code -- do not write that -- only here to show a common mistake
    ns.delegate = MyNetServiceDelegate()
    ns.resolve(withTimeout: TimeInterval(10))
    

    3- 帮助调试的技巧

    这里有一个调试这种 mDNS 解析的小技巧:在 Unix shell(例如 macOS)上,只需运行以下行:

    dig -p 5353 @224.0.0.251 myservice._http._tcp.local. SRV +short
    

    如果一个名为 myservice 的 http 服务正在运行,您将获得主机名和端口。通过我的示例,您将获得以下信息:

    0 0 8080 Mac-mini-de-Alexandre.local.
    

    因此,在尝试使用我在这里编写的 Swift 代码之前,只需检查您的服务是否已使用此 shell 命令正确宣布。

    最后,请注意,此基于 dig 的命令仅在每个 IPv4 网络接口上进行一次 IPv4 mDNS 查询,但使用 Apple Bonjour API,自动完成两组 mDNS 请求:一组使用 IPv4 到多播目标 224.0.0.251每个支持 IPv4 的网络接口,另一个支持 IPv6 的网络接口到多播目标 ff02::fb 的每个支持 IPv6 的接口。

    【讨论】:

    • 您能否提供一个具体使用 Bonjour 的示例?
    • @Grodriguez:我添加了一个示例。
    • 太棒了。这很有帮助。
    • 亚历克斯,你在 3 年前发布了这个并且你还在拯救生命!!在iOS13上运行,完美的swift 5!!
    猜你喜欢
    • 2020-10-24
    • 2020-05-05
    • 2016-05-24
    • 1970-01-01
    • 2021-12-31
    • 2011-04-15
    • 2018-08-08
    • 2014-05-27
    • 1970-01-01
    相关资源
    最近更新 更多