iOS Bonjour

287 阅读15分钟

使用苹果全家桶的同学们,肯定有过在多个设备之间无缝衔接的体验,比如隔空投送照片、文件,AirPlay电视投屏,还有自动共享热点密码,Apple Watch解锁Mac和iPhone,连续互通的相机/速绘/标记等等。它们的基本原理是通过Wi-Fi或蓝牙,在登录同一iCloud的设备之间快速同步数据。

问题来了,在局域网中设备之间要想通信,得知道对方的IP地址。以AirPlay投屏为例,第一步就是需要iPhone等终端设备找到局域网中的目标投屏设备(即电视),才能将音视频、图片或者屏幕内容投射到电视上。

而大多数情况下,设备的IP地址是通过动态分配的DHCP协议获取的。那么,设备之间是如何互相发现的呢?这就是Bonjour协议大显身手的时候了!

什么是Bonjour协议?

Bonjour是苹果公司实现的一套零配置(zero-configuration)网络协议。"Bonjour"这个词源于法语,意为“你好”或“早上好”。该协议旨在简化网络配置,让设备之间在局域网内轻松地相互发现和交流,就像人们打招呼一样。

通过Bonjour,用户不需要手动配置IP地址或设备名称,设备或应用程序可以自动检测所需的服务或其他可交互的应用程序,实现自动连接、通信和数据交换,无需用户干预。

局域网中设备的互联互通:image.png

一、Bonjour协议的工作原理是什么?

Bonjour是一种基于mDNS(Multicast DNS)协议的零配置网络发现服务。它可以在没有DHCP服务器或DNS服务器的情况下,使设备在本地网络中相互发现并建立连接。当一台设备加入网络时,它会向网络中的所有设备广播自己的服务信息,其他设备收到后就可以建立连接并使用相应的服务。

Bonjour的优点在于配置简单、使用方便。用户不需要手动设置IP地址、端口号等复杂的网络参数,只需要确保设备连接到同一个局域网中,Bonjour就可以自动完成服务发现和连接的过程。

1、Bonjour协议基础

Bonjour主要基于两个标准网络协议:mDNS(多播DNS)和DNS-SD(DNS服务发现),在标准DNS框架上进行构建扩展。

1.1 mDNS协议

mDNS协议基于UDP/IP,使用多播地址224.0.0.251和5353端口进行通信。mDNS协议通过多播查询和响应,实现了局域网内的主机名解析,而无需配置DNS服务器。mDNS协议数据包格式与标准的DNS协议一致,支持标准的DNS查询记录类型的同时,对其中的部分概念作了扩展。

其中,资源记录用于局域网中各个主机之间交换消息内容,包含以下几个关键字段:

NAME:表示消息内容

TYPE:表示消息内容的类型

进一步的,根据TYPE类型,可以定义以下几种关键DNS记录格式:

A 记录:主机名称和IPV4之间的对应关系

AAAA 记录:主机名称和IPV6之间的对应关系

PTR记录:记录了服务类型与服务实例名称之间的对应关系,一般用在查询和发现服务实例

SRV记录:记录了服务实例的主机名称和端口信息

TXT记录:提供服务的额外描述文本,以“key = value”的格式记录,如mac地址、设备id等

ANY 记录:任意类型,一般用于查询中

1.2 DNS-SD协议

mDNS协议定义了消息的基本结构和消息的传输过程。在此基础上,DNS-SD协议进一步明确定义了服务名称、服务实例名、域名长度/顺序等具体要素,使用PTR、SRV和TXT三种资源记录来完整描述一个服务,规定了简便的服务发现和描述方法。

其中,服务名称通常由“_”下划线和协议名称组合而成,并在域名结尾使用 "local" 作为固定标识,格式为<服务类型>.<域名>.local,如:_printer._tcp.local、_airplay._tcp.local

服务实例则通过其实例名进行标识,格式为<服务实例>.<服务类型>.<域名>,如:PrintsAlot._printer._tcp.local

MyMac._airplay._tcp.local

Bonjour协议通过上述两种协议实现了局域网内的主机名解析和服务注册与发现,为零配置网络提供基础。

2、Bonjour服务发现流程

要弄懂Bonjour的工作原理,我们只需思考上述mDNS协议和DNS-SD协议,是如何组合起来进行交互的即可。

Bonjour协议可以看作是mDNS和DNS-SD的有机结合。具体来说,DNS-SD协议通过PTR记录指向服务实例,并通过SRV记录提供实例的主机名和端口;拿到这些信息后,只需要通过mDNS解析主机名获取IP地址,就可完成从服务名称到IP地址映射关系,从而实现端到端的连接。需要注意的是,DNS-SD发布和查询的这些记录信息,都是依托在mDNS定义的多播组和端口号上进行传输的。

接下来我们举一个具体例子来说明,整个Bonjour服务发现过程是如何完成的。假设局域网中某个ipad设备想要发布音乐共享服务,主要包括以下三个步骤:

2.1 服务发布(Publication)

首先该设备会随机选择一个可用的链接本地IP地址,如:192.168.1.23,并向局域网中发布;第二步,它将启动mDNS响应器,并请求主机名 my-ipad.local.,确认没有冲突后使用该主机名;接着该设备在TCP端口1010上启动音乐共享服务;最后发布该音乐服务,并通过mDNS多播创建dns记录:

SRV记录:内容为服务实例名“小李的音乐服务._music._tcp.local.”,并指向主机名my-ipad.local.上的TCP服务端口1010

PTR记录:内容为服务名称“_music._tcp.local.”,并指向服务实例名称“小李的音乐服务._music._tcp.local.”

TXT记录:提供设备的额外信息,如MAC地址“MAC=D3:AA:E2:30:B0:E1”

当局域网内的其他设备接收后,会解析并缓存这些记录。

服务发布流程示例:image.png

2.2 服务发现(Discovery)

当某个客户端应用需要该音乐共享服务时,针对_music._tcp类型构造服务查询报文,通过mDNS多播查询请求到整个局域网;可提供该服务的设备收到查询请求后,会用一个PTR记录进行响应,这个响应记录包含了服务实例名“小李的音乐服务._music._tcp.local.”;客户端应用便可以从PTR记录中提取出服务实例名称,并将其添加服务器列表中。

服务发现流程示例:

image.png

2.3 服务解析(Resolution)

服务解析在完成服务发现后进行的。应用程序选择服务实例的名称,并向局域网组播查询对应的SRV记录;服务提供方响应后,返回该服务实例当前的主机名和端口号;应用程序拿到主机名后,再次发送多播mDNS查询请求,解析出主机名对应的IP地址。最后,应用程序根据获取的IP地址和端口号,与服务实例建立连接,完成解析。

服务解析流程示例:

image.png

至此,整个音乐共享服务的自动注册与发现的流程便完成了,全程高效便捷,不需要人工参与。通过建立好的网络通道,客户端设备便可以浏览并播放服务端的相关音乐资源了。

经过多年发展,Bonjour已经成为Apple等平台的标准服务,它为零配置网络提供了一个开放、实用、高效的解决方案。Bonjour基于mDNS和DNS-SD协议,使其与现有网络基础设施高度兼容,已经广泛应用到了个人、企业网络及IoT设备中,大幅简化了网络配置和管理。未来,随着智能硬件业务的不断增长,相关技术在网络互联互通方面还具有广阔的应用和发展前景。

二、Bonjour在苹果设备上的应用

作为苹果公司开发的一款软件,Bonjour在苹果的各种设备上都得到了广泛应用。在Mac电脑上,用户可以通过Finder的"共享"功能来访问其他设备上的文件,或者将自己的文件夹共享给其他设备。例如,在家庭网络中,我们可以将Mac上的照片、视频等文件共享给其他家庭成员的iPhone或iPad,方便大家随时欣赏和回味。

在iOS设备上,Bonjour更多地用于打印机共享和AirDrop文件传输等场景。通过Bonjour,我们可以在iPhone或iPad上直接打印文档,而无需另外安装打印机驱动程序。同时,AirDrop也利用了Bonjour技术,使得iOS设备之间可以快速方便地共享照片、视频等文件。

三、跨平台使用Bonjour的方法

尽管Bonjour是苹果公司开发的软件,但它并不局限于苹果设备。事实上,苹果还推出了用于Windows系统的Bonjour软件,使得Windows设备也能够加入到Bonjour网络中,实现与苹果设备的互联互通。

在Windows电脑上安装Bonjour非常简单,只需要从苹果官网下载对应的安装包,按照提示完成安装即可。安装完成后,Windows电脑上就会出现Bonjour服务,可以在网络邻居中发现局域网内的苹果设备并访问其共享服务。例如,我们可以在Windows电脑上直接打印Mac电脑共享的文档,或者访问Mac上的共享文件夹。

四、内容延伸:

除了文件共享和打印机共享,Bonjour还可以用于很多其他的应用场景,例如:

  1. 音频/视频流媒体共享:通过Bonjour,我们可以将Mac或iOS设备上的音乐、视频等多媒体内容共享给其他设备,实现局域网内的流媒体播放。

  2. 智能家居设备连接:很多智能家居设备都支持Bonjour协议,例如飞利浦Hue智能灯泡、iRobot扫地机器人等。通过Bonjour,我们可以在iPhone或iPad上快速发现并控制这些设备。

五、Bonjour可以做什么

1、 IP获取

在传统网络环境下,设备的IP地址通过两种方式获取,一种是静态配置,通过手工方式为设备指定一个IP地址,一种是动态配置,设备通过路由器的DHCP服务获得动态的IP地址。

在无中心服务器的网络环境下,没有中心服务器提供DHCP服务,用户手工配置IP地址也很不方便,这就需要一种新的方式来帮助设备获取IP地址,就是希望设备可以主动为自己指定一个可用的IP地址。

在IPV6环境下,IPV6协议本身就提供了设备自指定IP地址的能力,所以实现很简单,直接使用IPV6的协议支持就可以了。

在IPV4环境下,Bonjour使用了随机指定IP地址的方法,首先为设备随机指定一个属于本地网段的IP地址,然后检查该地址在本地是否有冲突,如果有冲突就随机生成另一个新的IP地址,直到找到可用IP地址为止。

2、 名称解析

在传统网络环境下,名称和IP地址的对应关系是通过DNS服务解析的。当一个设备需要访问一个域名,如“www.abc.com”,设备将“www.abc.com”发给DNS服务器,服务器返回该域名对应的IP地址,设备再使用返回的IP地址对目标服务器进行访问。

在没有中心服务器的网络环境中,没有DNS服务器提供域名解析服务,名称解析变成一个严重问题。针对这一问题,业界的解决方案是mDNS,中文叫“组播DNS”,在标准文档RFC6762中定义。

“组播DNS”的原理很简单,当一个设备需要解析一个名称时,如“abc.local.”,这个设备通过UDP协议向本地网络中的所有设备广播一个消息,问谁是“abc.local”,本地网络中如果有一个设备认为自己是“abc.local”,它就给出响应,说出自己的IP地址。

因为“组播DNS”基于UDP协议,采用广播消息的方式,所以不需要一个中心服务器提供DNS解析服务就可以完成本地的名称解析。

Bonjour也是基于mDNS协议的,不过Bonjour在mDNS协议上作了扩展,加强了设备响应“组播DNS”请求的能力。在Bonjour协议下,应用只需要对某个名称进行注册,就可以将响应“组播DNS”请求的工作交由底层处理。也就是说在Bonjour协议下,应用不需要侦听本地网络的“组播DNS”请求并进行响应,这些工作由底层系统完成。

为了区分全球域名和本地域名,mDNS协议使用“.local.”作为本地域名的根域名。

3、 服务发现

当一个提供服务的设备获取IP地址,并自我指定一个域名后,其实还是不能满足用户的需求。因为用户需要的是某种服务,如打印服务,web服务,用户并不关心这些服务对应的服务器名称和它的IP地址。

为了让用户更容易发现本地网络中的各种服务,Bonjour为设备提供了服务发现的能力。

Bonjour提供的“服务发现”能力基于一个简单直接的规定,就是提供服务的设备在按以下标准对服务进行注册:“名称.服务类型.传输协议类型.local.”,比如:“DamonWebServer._http._tcp.local.”,又比如“DummiesWebServer._http._tcp.local.”。

这样,当一个设备使用希望查找http服务的时候,Bonjour会去查找本地网络中注册过的包含"_http"的服务,然后将结果返回给用户选择。这时用户面对的是“DamonWebServer”和"DummiesWebServer",用户可以不去关心到底这两个web服务到底在那台设备上,该设备的IP地址是什么。

六、 如何使用Bonjour

对于最终用户来讲,Bonjour基本上是透明的,他们不需要了解如何去使用Bonjour,往往都是应用开发者去考虑如何使用Bonjour。

对于应用开发者来讲,他们需要考虑有两部分,一是如何作为Bonjour客户端去发现使用本地服务,二是如何作为服务端如何注册Bonjour服务

1、 如何作为Bonjour客户端去发现本地服务

iOS开发可以使用NSNetService框架中的NSNetServiceBrowser类去发现本地服务。

基本过程如下:

首先创建NSNetServiceBrowser实例:

serviceBrowser = [[NSNetServiceBrowser alloc] init];

然后指定NSNetServiceBrowser实例的代理,所指定的代理需要实现“NSNetServiceBrowserDelegate”协议。由实现以上协议的代理对服务查找相关的事件进行响应。这里指定本实例为NSNetServiceBrowser代理,由本例对服务查找的事件进行响应:

serviceBrowser.delegate = self;

接着使用NSNetServiceBrowser实例的searchForServicesOfType方法查找服务,方法中可以指定需要查找的服务类型和查找的域。以下样例查找“local.”域中的“http”服务:

[serviceBrowser searchForServicesOfType:@"_http._tcp." inDomain:@"local."];

最后,在“NSNetServiceBrowserDelegate”的以下方法中响应“didFindService”事件,就是找到服务的事件。其中的netService参数就是找到的服务,在netService参数中可以得到服务地址,服务主机名等信息。

- (void)netServiceBrowser:(NSNetServiceBrowser *)netServiceBrowser didFindService:(NSNetService *)netService moreComing:(BOOL)moreServicesComing 
{}
2、 如何作为服务端注册Bonjour服务

要注册成为Bonjour服务,开发者可以直接创建NSNetService实例,并通过initwithDomain: type: name: port:方法进行初始化,指定服务的域,类型,名称和端口,样例代码如下:

service = [[NSNetService alloc] initWithDomain:@"local." type:@"_http._tcp." name:@"DamonWebServer" port:port];

NSNetService创建成功后,可以通过setDelegate指定代理,同时通过publish方法发布注册服务:

[service setDelegate:self];
        [service publish];

其中指定的代理需要遵从“NSNetServiceDelegate”协议,可以对服务发布成功,发布失败等事件。

正常来讲,如果需要发布一个服务,需要在发布服务之前准备好服务并启动它。不过NSNetService的publish方法并不依赖它所发布的服务,不管服务是否准备好,是否启动,NSNetService的publish都可以成功将服务发布出去,只不过服务发布出去后其它使用这个服务的客户端会发现这个发布出来的服务是个无效服务。

参考: developer.apple.com/bonjour/

blog.csdn.net/yueqian_scu…

www.cnblogs.com/yuweifeng/p…

  1. 多人协作应用:一些多人协作的应用程序也利用了Bonjour技术,例如Sketch、Principle等设计软件。通过Bonjour,多个设计师可以在局域网内实时分享设计稿,提高工作效率。