本文由嵌入式企鹅圈原创团队成员-华南师范大学物联网创新中心Hende_Zhu先生执笔。
WIFI物联网解决方案中,通常我们需要对设备进行绑定,需要通过某种方法先对设备进行发现,比如微信硬件采用广播的方式,定时向外发送上线消息或者采用一问一答的方式进行发现,Bonjour是由苹果公司实现的一种零配置网络(Zeroconf)协议,它是一种基于服务的设备发现协议,不仅能够自动获取有效IP地址,还可以通过查询服务的方式来找到设备地址,只要双方约定好服务(service)的名称,设备的IP地址和端口都是可以变化的!
一、mDNS协议和DNS-SD协议
Bonjour协议是基于mDNS(Multicast DNS)协议和DNS-SD(DNS Service Discovery)协议开发实现,因此有必要先在这里给大家介绍一下这两个协议。
1.1 mDNS协议介绍
mDNS协议适用于局域网内没有DNS服务器时的域名解析,设备通过组播的方式交互DNS记录来完成域名解析,约定的组播地址是:224.0.0.251,端口号是5353,mdns协议使用DNS协议一样的数据包,由头部和数据段两部分(大家可以自行去了解DNS数据包的格式啦,在这里不展开介绍了):
mDNS的一个使用情景是这样的:
设备d通过组播(224.0.0.251:5353),询问a.local地址是?
设备a知道有人查询它后,也是通过同样的组播组回复它的地址信息(通过回复用于IPv4的A类型DNS记录(A Record)或者用于IPv6的AAAA类型的DNS记录,A记录和AAAA记录分别用于将域名转换成IP地址),这里组播内的所有人b, c, d都会收到,它们会将a.local的ip地址等信息(如TTL值)刷新到mDNS缓冲区中。
mDNS协议和DNS协议还有些不同,mDNS只能用于局域网内部,并且它只接受解析主机名前缀为.local的域名,因此mDNS也是可以和DNS在同一台设备上共存的,以及它们存储记录的区域是分开的。
除此之外,mDNS还有其它的作用,例如在零配置网络中给自己分配域名,设备给自身选择一个域名后,然后通过发送记录类型为”any”的mDNS包来查询局域网内是否有同名,如果没有设备就会把这个名字作为自己的域名。
1.2 DNS-SD协议介绍
接下来再介绍一下DNS-SD协议,即DNS based Service Discovery,基于DNS的服务发现主要用到DNS现有的三种类型记录(Record Type):PTR记录、SRV记录、TXT记录,其中:
1)服务发现:设备会先发送一个查询PTR记录的数据包到组播组,所查询服务格式为:
<service>.<transport>.<domain>
service表示的是要查询的服务,transport表示的是传输的协议:TCP还是UDP,domain表示查询的域,在mDNS中为.local,接着具有对应服务的设备会响应一系列本设备上所具有的服务实例:
<instance>.<service>.<transport>.<domain>
instance表示服务的实例名,虽然收到<instance>.<service>.<transport>.<domain>,但是只有instance才会显示给用户看,比如:要查询一个_easylink._tcp.local的服务,具有这个服务对应实例的设备会响应一条PTR记录:EMW3031 Module#500A3F._easylink._tcp.local,即表示EMW3031 Module#500A3F为_easylink._tcp.local的一个实例,设备收到后只会显示EMW3031 Module#500A3F供用户看,它是UTF-8编码的。
可以看出,DNS-SD的PTR记录所代表的意思是区别于传统DNS的PTR记录的含义的,并且DNS-SD下的PTR记录用于记录服务到服务实例的映射。
2)获取服务实例的主机名和端口号:上述多个服务实例instance显示供用户选择确定一个后,就需要查询记录服务实例的主机名和端口号,即查询SRV记录。
设备会发送一个mDNS请求,然后具有所请求中服务实例的设备会响应SRV记录,SRV记录记录了这个服务实例对应的主机名和端口号以及TTL信息,一条SRV记录的例子是:
EMW3031 Module#500A3F._easylink._tcp.local. 3 IN SRV 0 0 8002 EMW3031 Module#500A3F.local.
DNS下的SRV记录的格式为:
_service._proto.name. TTL class SRV priority weight port target.
在DNS-SD中,priority和weight无效,一般置为00 00,port和target即为端口号和主机名。
因此SRV记录用于记录服务实例到端口号和主机名的映射,即便端口号可变也没有关系。
3)服务实例更详细的信息:有时候,一个服务实例除了所在设备的端口号和主机名这些信息以外,还可以提供更多的附加参数信息,服务实例的附加信息记录在TXT记录中,以”key = value”的格式记录,如提供设备的MAC地址:
MAC=D0:BA:E4:50:0A:3F
二、Bonjour协议原理
前面介绍了mDNS协议以及DNS-SD协议,其实基本上就已经展开介绍了Bonjour协议的细节,接下来再来理解Bonjour就相当轻松了。Bonjour协议可以理解为mDNS协议和DNS-SD协议的结合,其实大家在继续往下看之前可以自己想一下如何将两个协议结合起来呢?DNS-SD已经找到了提供服务的端口号和主机好了,最后再做进一步的主机名到IP地址的解析就完成了Bonjour协议的整个过程,当然结合的时候DNS-SD所发送的三种记录都是通过mDNS规定的组播组和端口号(224.0.0.254:5353)发送出去的,但是DNS-SD是不依赖mDNS协议而存在的。
Bonjour协议提供三部分功能:通告服务、发现服务、解析服务,这是三个动宾词组哈。在物联网中,设备在本地记录一个服务往往需要提供服务相关的SRV记录、PTR记录以及TXT记录相关的信息,用于最后组装mDNS数据包发送出去。
在没有DHCP分配IP地址和没有设置静态IP地址情况下,通过Bonjour协议还可以自己在局域网内获取有效的IP地址以及主机名,但是需要我们配置好路由的信息如子网掩码等,它会生成一个IP,然后询问局域网内是否有冲突,如果没有冲突就将这个IP占为己有,如果有冲突,就会更换一个IP,继续查询,主机名也是利用同样的方法获得。
通告服务用于设备告之局域网内其他人本设备的服务信息,一般包括发送SRV记录和PTR记录,这些记录被其它mDNS设备记录在本地的存储区中。
发现服务用于查询一个指定的服务,然后具有该服务的设备会响应PTR记录,告诉查询的设备有这样的服务并且服务实例的名称是什么。
解析服务发生在完成服务发现之后,获得了服务实例后供用户选择,再下一步就要进行解析,首先根据服务实例获得该设备的主机名以及端口,最后再根据主机名来获取IP地址。
经过以上一步步交互就可以获得了目标设备的IP地址和端口号了,然后就可以根据选择的传输协议TCP或者UDP进行通信。
三、mDNS数据包
庆科物联的设备端已经实现了Bonjour协议的主要功能,以下是基于其设备端发现过程用Wireshark抓的包,其中IP地址为192.168.191.2表示的是手机端,192.168.191.3表示的是完成配网后的设备端,它们在同一个局域网内。
服务发现:由手机APP发送查询_easylink._tcp.local服务
服务解析:设备端一次性响应了PTR记录、SRV记录、TXT记录以及A记录:
每条记录展开为:
嵌入式企鹅圈原创团队由阿里、魅族、nvidia、龙芯、炬力、拓尔思等资深工程师组成。百分百原创,每周两篇,分享嵌入式、Linux、物联网、GPU、Android、自动驾驶等技术。欢迎扫码关注微信公众号:嵌入式企鹅圈,实时推送原创文章!