Android组播域名服务

Multicast DNS is a way of using familiar DNS programming interfaces, packet formats and operating semantics, in a small network where no conventional DNS server has been installed.

上文是来自http://www.multicastdns.org/的说明

1.1Bonjour背景介绍

Bonjour是法语中的Hello之意。它是Apple公司为基于组播域名服务(multicast DNS)的开放性零配置网络标准所起的名字。使用Bonjour的设备在网络中自动组播它们自己的服务信息并监听其它设备的服务信息。设备之间就像在打招呼,这也是该技术命名为Bonjour的原因。Bonjour使得局域网中的系统和服务即使在没有网络管理员的情况下也很容易被找到。

Bonjour技术在Mac OS以及Itunes、Iphone上都得到了广泛应用。为了进一步推广,Apple通过开源工程mdnsresponder将其开源出来。在Windows平台上,它将生成一个后台程序mdnsresponder。在Android平台上(或者说支持POSIX的Linux平台)它是一个名为mdnsd的程序。

我们重点需要了解android平台的mdnsresponder。

Android组播域名服务_第1张图片
图一


1.2Bonjour用处

一个简单的例子:在局域网中,如果要进行打印服务,必须先知道打印服务器的IP地址。此IP地址一般由IT部门的人负责分配,然后他还得全员发邮件以公示此地址。有了Bonjour以后,打印服务器自己会依据零配置网络标准在局域网内部找到一个可用的IP并注册一个打印服务,名为“print service”之类的。当客户端需要打印服务时,会先搜索网络内部的打印服务器。由于不知道打印服务器的IP地址,客户端只能根据诸如"print service"的名字去查找打印机。在Bonjour的帮助下,客户端最终能找到这台注册了“print service”名字的打印机,并获得它的IP地址以及端口号。

从Bonjour角度来看,该技术主要解决了三个问题:

·Addressing:即为主机分配IP。Bonjour的Addressing处理比较简单,即每个主机在网络内部的地址可选范围内找一个IP,然后查看网络内部是否有其他主机再用。如果该IP没有被分配的话,它将使用此IP。

·Naming:Naming解决的是host名和IP地址的对应关系。Bonjour采用的是Multiple DNS技术,即DNS查询消息将通过UDP组播方式发送。一旦网络内部某个机器发现查询的机器名和自己设置的一样,就回复这条请求。此外,Bonjour还拓展了MDNS的用途,即除了能查找host外,还支持对service的查找。不过,Bonjour的Naming有一个限制,即网络内部不能有重名的host或service。

·Service Discovery:SD基于上面的Naming工作,它使得应用程序能查找到网络内部的服务,并解析该服务对应的IP地址和端口号。应用程序一旦得到服务的IP地址和端口号,就可以直接和该服务建立交互关系。

下面我们将介绍BonjourAPI中使用最多的三个函数,它们分别是服务注册、服务查询和服务解析。理解这三个函数的功能也是理解mdns的基础。

Android对应的代码为external/mdnsresponder/mDNSShared/dns_sd.h

服务注册的API为DNSServiceRegister,原型如图所示:

Android组播域名服务_第2张图片
图二

该函数的解释如下:

·sdRef:代表一个未初始化的DNSService实体。其类型DNSServiceRef是指针。该参数最终由DNSServiceRegister函数分配内存并初始化。

·flags:表示当网络内部有重名服务时的冲突处理。默认是按顺序修改服务名。例如要注册的服务名为“printer”,当检测到重名冲突时,就可改名为“printer(1)”。

·interfaceIndex:表示该服务输出到主机的哪些网络接口上。值-1表示仅对本机支持,也就是该服务的用在loop接口上。

·name:表示服务名,为空的话就取机器名。

·regtype:服务类型,用字符串表达。Bonjour要求格式为"_服务名._传输协议",例如"_ftp._tcp"。目前传输协议仅支持TCP和UDP。

·domian和host一般都为空。

·port表示该服务的端口。如果为0的话,Bonjour会自动分配一个。

·txtLen以及txtRecord字符串用来描述该服务。一般都设置为空。

·callBack:设置回调函数。该服注册的请求结果都会通过它回调给客户端。

·context:上下文指针,由应用程序设置。

当客户端需要搜索网络内部特定服务时,需要使用DNSServiceBrowserAPI,其原型如图2所示:

Android组播域名服务_第3张图片
图三

其中:

·sdref、interfaceIndex、regtype、domain以及context含义与DNSServiceRegister一样。

·flags:在本函数中没有作用。

·callBack:为DNSServiceBrowser处理结果的回调通知接口。

当客户端想获得指定服务的IP和端口号时,需要使用DNSServiceResolveAPI,其原型如下图所示:

Android组播域名服务_第4张图片

其中:

·name、regtypedomain都从DNSServiceBrowse函数的处理结果中获得。

·callBack用于通知DNSServiceResolve的处理结果。该回调函数将返回服务的IP地址和端口号。

1.3Android Says Bonjour

Android平台的Bonjour架构可由下图图表达:

Android组播域名服务_第5张图片
图四

由上图可知,Android拓展了原有的Bonjour架构,改变如下:

·在Netd中增加了MDnsSdListener对象,它一方面通过socket和framework上层对象通信,另一方面通过Bonjour API和mdnsd通信(也是基于Socket的跨进程通信)。从mdnsd角度来看,它是最懂Bonjour API的”人“了。

·System_process进程新增NsdService。Nsd是Network Service Discovery的缩写。NsdService通过socket和位于Netd中的MDnsSdListener通信。

·App借用NsdManager API通过Binder技术和System_process的NsdService通信。

1.3.1MDnsSdListener介绍

MDnsSdListener在Android Bonjour架构中扮演着转换器的角色:

·一方面它处理来自framework 上层NsdService的请求,并通过Bonjour API将其转换成mdnsd能懂的“语言”以驱动其工作。

·另一方面它接收来自mdnsd的信息,并把它们通报给NsdService。

在系统中该代码在Netd中,system/netd/MDnsSdListener.cpp。

Android组播域名服务_第6张图片

由上图可知:

·MDnsSdListener的内部类Monitor用于和mdnsd进程通信,它将调用前面提到的Bonjour API。

·Monitor内部针对每个DNSService都会建立一个Element对象,该对象通过Monitor的mHead指针保存在一个list中。

·Handler是MDnsSdListener注册的Command。

下面将简单介绍MDnsSdListener的运行过程,其主要工作可分成三步:

·Netd创建MDnsSdListener对象,其内部会创建Monitor对象,而Monitor对象将启动一个线程用于和mdnsd通信,并接收来自Handler的请求。

·NsdService启动完毕后将向MDnsSdListener发送"start-service"命令。

·NsdService响应应用程序的请求,向MDnsSdListener发送其他命令,例如"discovery"等。Monitor将最终处理这些请求。

Android组播域名服务_第7张图片

·Monitor的threadStart线程将调用其run函数,该函数通过poll方式侦听包括mCtrlSocketPair在内的socket信息。

·当NsdService发送"start-service"命令后,Handler的runCommand将执行Monitor的startService函数。

starService将启动mdnsd,如下面代码所示:

Android组播域名服务_第8张图片

MDS_SERVICE_NAME宏代表字符串"mdnsd",property_set("ctl.start",MDNS_SERVICE_NAME);这个方法是android启动service独特的方式,可以在device目录init.rc下找到该定义mdnsdf服务:

Android组播域名服务_第9张图片

当NsdService发送注册服务请求时,Handler的serviceRegister函数将被调用,代码如下所示

Android组播域名服务_第10张图片

DNSServiceRegister内部将把请求发送给mdnsd去处理,处理的结果通过MDnsSdListenerRegisterCallback返回,该函数最终会通过socket把信息传递给NsdService去处理。

1.3.2NsdService介绍

对所有Android App来说,就是通过NsdService来实现自己的服务。

图9列出了NsdService中的几个重要成员,其中:

·NsdService从INsdManager.stub派生。这个类也是Android的特色产品,由INsdManager.aidl文件生成。

·NsdService内部工作将通过NsdStateMachine及内部的三个状态对象(DefaultState、EnableState、DisableState)驱动。

·NsdService通过NativeDaemonConnector和Netd中的MDnsSdListener建立socket通信。

mNativeConnector = newNativeDaemonConnector(new NativeCallbackReceiver(), "mdns", 10,MDNS_TAG, 25);

通过socketname(mdns)跟MDnsSdListener通信,其中这个socketname在device/rockchip/rksdk/init.rc文件定义:

service netd /system/bin/netd

class main

socket netd stream 0660 root system

socket dnsproxyd stream 0660 root inet

socket mdns stream 0660 root system

·类NativeCallbackReceiver用来通知NsdService来自Netd的消息。

·NsdService中的NsdServiceInfo,它就是Network Service在Android Bonjour中的代表。其包含的内容有服务名、服务类型、IP地址和端口号等。

·类NativeCallbackReceiver用来通知NsdService来自Netd的消息。

·NsdService中的NsdServiceInfo,它就是Network Service在Android Bonjour中的代表。其包含的内容有服务名、服务类型、IP地址和端口号等。

1.3.3NsdChat案例介绍

Android SDK新增了一个NsdChat例子用于向开发者介绍Android平台中Nsd的使用方法。相关文档位于http://developer.android.com/training/connect-devices-wirelessly/nsd.html。案例的源码位于Android4.4源码根目录/development/samples/training/NsdChat下。

该例描述了一个简单的聊天程序,故其命名为NsdChat。Nsd在此例中的作用就是注册并搜索网络内的聊天服务。

你可能感兴趣的:(Android组播域名服务)