在局域网内通信,就必须知道对方的IP地址和端口,苹果开源的mdnsResponder,就是利用mdns组播协议,通过服务域名,来获取相应ip地址的一种方式。
比如我们有一个摄像头,在联网的情况下,同一个局域网下的app想发现这个摄像机,并和摄像机建立联系。
这样一个需求,需要摄像头调用mDNS_Register,通过传参告知mdns库,在指定的port上注册一个did._ipcxx._tcp.local的服务, 然后自己开一个socket,绑定port口,等待来自APP的数据。
APP要去找摄像机,所以调用DNSServiceBrowse,传入服务类型_ipcxx._tcp和域local, 在局域网内就能找到一条 did._ipcxx._tcp.local的服务, 再调用DNSServiceResolve,就可以得到ipc的主机名和端口号, 通过主机名,调用gethostbyname,就可以获取到摄像机的ip地址。 服务的名字使用摄像机的did,方便app应对多个摄像机,同时方便验证合法性。
有了ip和port,就可以创建一个socket,去连接到摄像头,就开始发送数据了。
至此,一个局域网自动发现功能就完成了,我们不需要了解mdns组播协议,仅仅调用苹果的api,就获取到了想要的摄像机的ip。
下面介绍苹果开源源码的移植和它的demo代码。
源码地址在:https://opensource.apple.com/tarballs/mDNSResponder/, 版本为:mDNSResponder-878.30.4.tar.gz
解压后目录结构:
这里面有针对不同系统的文件夹,我们不需要关心,用得上的是mDNSPosix/mDNSCore/mDNSShared三个目录。
建议读本目录和mDNSPosix下的README.TXT,里面说的很细致。
我们是Linux系统,所以进到mDNSPosix目录, 里面的各个文件我们暂时也不需要关心,这是好几个应用程序的源代码。
执行 make os=linux, 先在我们的x86linux上编译一遍, 如果你想在linux上直接调试,可以执行sudo make install os=linux, 他会安装并执行一个mdnsd的应用程序,是mDNS的常驻进程,常用调试应用dns-sd,就需要依赖这个程序才能实现mdns服务发现,参见readme文件。
在../Clients/build目录下,执行./dns-sd就能看到命令选项, 可以注册一个service,可以再开一个shell,同样执行./dns-sd 去发现刚才注册的服务。调试很好用。
但是最终要把mdns移植到我们的嵌入式linux上,所以我们不能用mdnsd, 也不用dns-sd。
在Makefile中, 需要我们直接修改工具链和编译参数,在build下编译出可以在嵌入式设备上运行的程序。
刚才的make中os参数是必须的,我们指定linux,就会到这里来,在这里我们可以定义我们自己的arm gcc,可以加我们自己的编译选项CFLAGS, 同时去掉CFLAGS_OS中的-DHAVE_IPV6 -DTARGET_OS_LINUX。
rm -rf objects, 删除前一次的编译文件。同样 make os=linux,直到编译成功。在build/prod目录下,就是我们生成的可执行文件,嵌入式设备上,执行mDNSClientPosix, 就可以看到同一个局域网下,你刚才在linux上用dns-sd注册的服务, 执行mDNSResponderPosix,就可以注册一个服务。查看代码client.c 和 responder.c,你会了解服务注册和搜索的过程。
这个responder.c,就是我们嵌入式设备所需要的base代码,你自己的应用逻辑,都可以在这里实现。
怎么把它移植到我们自己的代码库中?
编译的时候,在编译mDNSResponderPosix时,会打印出它所依赖的.c文件,把这些.c文件单独摘出来,把.h文件也拿出来,单独见一个目录,就可以使用这些.c文件,执行自己的make,生成responder可执行文件了。
至此,整个移植的过程就结束了。
调试过程中,通过对client.c responder.c Clinents/dns-sd.c的学习,就会了解各个接口的应用,从而融会贯通。