卓悦:按名称搜索服务 [英] Bonjour: Search for a service by name

查看:128
本文介绍了卓悦:按名称搜索服务的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

  1. 调用browse以检测给定类型的所有服务(例如,可能是_http._tcp)
  2. 对于找到的每个服务,调用serviceFound.服务名称在此处报告
  3. 在找到的每个服务上致电resolve
  4. 对于每个已解决的服务,称为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.

I have an application that needs to search and resolve a Bonjour-advertised service whose name is known in advance. Most Bonjour examples I have found related to service discovery are structured more or less like this:

  1. Call browse to detect all services of a given type (for example, this could be _http._tcp)
  2. For each service found, serviceFound is called. Service names are reported here
  3. Call resolve on each service found
  4. For each service resolved, serviceResolved is called

Is it possible with Bonjour to skip the "discovery" stage, since I know in advance the name of the service I want to resolve? Can I just detect and resolve a service with a known name?

解决方案

1- Answer

Yes, you can start with the 3rd step if you already know the name of the service. This is because this step is performed through a DNS lookup for a SRV record with the name of the service sent to a well-known multicast address. So, no previous information is needed to make this call, and the mDNS responder must be stateless, since the underlying DNS protocol is stateless (each response is bound to a unique request - no state maintained between several requests).

2- Example

Here is an example I've just written with Swift, that has passed tests running on my iPad to find a service running on my Mac Mini. So, we suppose the domain is local, the service type is _http._tcpand the name of the service is myservice, running on host Mac-mini-de-Alexandre.local and listening to TCP port 8080.

To track informations about the service, for instance its hostname and TCP port, we define a class that implements the NetServiceDelegate protocol:

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

This new class will be used to instantiate the delegate for a NetService instance.

So, we create a NetService instance corresponding to the service we already know about, that we store in the long-term with a static constant property of some main class:

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

It is stored in the long term because it must not be deallocated before we find our service.

Note that the delegate property in class NetService is declared unowned(unsafe). So, we also need to create a reference to the delegate instance:

static let ns_deleg = MyNetServiceDelegate()

When we want to resolve the service, we may write:

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

The delegate instance will be called later (resolve() is a non-blocking method) if the service is found, and in this case, it will print the hostname and port.

Here is the output I got in my Xcode output window:

Mac-mini-de-Alexandre.local. 8080

Finally, note that because of the unowned reference, it would be a mistake to write the following code (the delegate instance would be shortly deallocated):

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

3- Trick to help debugging

Here is a little trick to debug such a mDNS resolution: on a Unix shell (macOS for instance), just run the following line:

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

If an http service with name myservice is running, you will get the host name and port. With my example, you will get the following:

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

So, before trying to use the Swift code I've written here, just check that your service is correctly announced with this shell command.

Finally, note that this dig based command only makes one IPv4 mDNS query on each IPv4 network interface, but using the Apple Bonjour API, two groups of mDNS requests are done automatically: one with IPv4 to the multicast destination 224.0.0.251 on each network interface that supports IPv4, and another with IPv6 to the multicast destination ff02::fb on each interface that supports IPv6.

这篇关于卓悦:按名称搜索服务的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆