Bonjour:按名称

时间:2017-09-01 12:03:09

标签: network-programming bonjour zeroconf

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

  1. 调用browse以检测给定类型的所有服务(例如,这可能是_http._tcp
  2. 对于找到的每项服务,都会调用serviceFound。服务名称在此处报告
  3. 在找到的每项服务上致电resolve
  4. 对于已解决的每项服务,serviceResolved称为
  5. Bonjour是否有可能跳过“发现”阶段,因为我事先知道要解决的服务名称?我可以检测并解析具有已知名称的服务吗?

1 个答案:

答案 0 :(得分: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类中的delegate属性声明为 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 on支持IPv4的每个网络接口,以及支持IPv6的每个接口上的IPv6到组播目标ff02 :: fb的另一个网络接口。