我有一个应用程序需要搜索和解析一个预先知道名称的 Bonjour 广告服务。我发现的大多数与服务发现相关的 Bonjour 示例的结构或多或少是这样的:
browse
以检测给定类型的所有服务(例如,这可能是_http._tcp
)serviceFound
都会调用。服务名称在此处报告resolve
找到的每个服务serviceResolved
称为Bonjour 是否可以跳过“发现”阶段,因为我事先知道要解析的服务的名称?我可以只检测和解析具有已知名称的服务吗?
1-答案
是的,如果您已经知道服务的名称,则可以从第 3 步开始。这是因为此步骤是通过 DNS 查找 SRV 记录来执行的,其中 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 到支持 IPv6 的每个接口上的多播目的地 ff02::fb。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句