zl程序教程

您现在的位置是:首页 >  移动开发

当前栏目

Android局域网通信机制初探

Android通信 机制 初探 局域网
2023-09-14 09:04:38 时间
###简介 在网络上,两台主机要进行通信,就必须互相知晓对方的IP地址,在Internet上,一台主机的IP地址可能是经常发生变化的,并且IP地址非常难以记忆,因此产生了将主机名(域名)解析为IP地址的DNS服务。在局域网内,往往不存在DNS服务器,而在使用了DHCP的局域网内,各主机的IP往往也是不固定的,因此在主机之间进行IP解析是有一定困难的,为解决这个问题,mDNS应运而生。

在网络上,两台主机要进行通信,就必须互相知晓对方的IP地址,在Internet上,一台主机的IP地址可能是经常发生变化的,并且IP地址非常难以记忆,因此产生了将主机名(域名)解析为IP地址的DNS服务。在局域网内,往往不存在DNS服务器,而在使用了DHCP的局域网内,各主机的IP往往也是不固定的,因此在主机之间进行IP解析是有一定困难的,为解决这个问题,mDNS应运而生。

在计算机网络中,多播域名系统(multicast Domain Name System, mDNS)被用于在一个不包含DNS服务器的局域网络中做域名解析服务。

RFC 6762定义了mDNS的规范,它使用UDP协议承载,在IPv4网络上,使用组播地址224.0.0.251,在IPv6网络上,使用组播地址ff02::fb, 5353端口来广播报文。Apple的Bonjour就是一个基于mDNS的服务。

使用mDNS服务的主机主要执行两个动作:Register和Discover

Register

顾名思义,Register即为主机在网络上发布一个服务,一个最基本的服务包含以下信息:

服务类型:表明该主机提供服务的类型,例如,一台提供HTTP访问服务的主机发布的服务类型为_http._tcp 服务名称:主机名,类似web网站的域名 端口:表明该服务所在的端口 Discover

Discover在网络内查找提供相应服务的主机,查找操作只需提供服务名称即可。

提供mDNS服务的主机在加入网络时,会向发送一个广播消息,表明自己的身份,在收到查询请求时,会回复自己的IP地址和端口信息;一个主机发起discover请求时,同样会发送一个广播消息,网络内所有能提供服务的主机都会回复此广播消息。

使用JmDNS库

JmDNS是一个使用Java实现的用于在局域网内进行服务注册和发现的mDNS服务,它完全兼容Apple Bonjour,可工作在JDK 1.6+。

JmDNS在maven中的groupId为javax.jmdns, artifactId为jmdns

JmDNS jmdns = JmDNS.create();

注册服务是可选的,如果只需要使用网络发现,而自己不提供服务的话可以跳过这一步。注册服务需要提供一个ServiceInfo对象,用于描述所提供服务的信息。

//创建ServiceInfo

String serviceType = "_test._tcp.local.";

String serverName = "JmDNS Test";

int port = 1234;

ServiceInfo serviceInfo = ServiceInfo.create(serviceType, serverName, port); 

//注册服务

jmdns.registerService(serviceInfo);

发现服务需要创建一个ServiceListener对象,用来处理网络发现过程中各阶段的回调。

jmdns.addServiceListener("_http._tcp.local", listener = new ServiceListener() {

 @Override

 public void serviceResolved(ServiceEvent ev) {

 String addr = "";

 if (ev.getInfo().getInetAddresses() != null ev.getInfo().getInetAddresses().length 0) {

 addr = ev.getInfo().getInetAddresses()[0].getHostAddress();

 System.out.println("Service resolved: " + ev.getInfo().getName() +" == "+ addr + ":" + ev.getInfo().getPort() );

 @Override

 public void serviceRemoved(ServiceEvent ev) {

 System.out.println("Service removed: " + ev.getName());

 @Override

 public void serviceAdded(ServiceEvent event) {

 // Required to force serviceResolved to be called again (after the first search)

 jmdns.requestServiceInfo(event.getType(), event.getName(), 1);

 }});

在解析过程中,当一个新服务被发现时,serviceAdded()方法会被回调,在回调中我们可以使用requestServiceInfo()方法发起一个解析请求,当服务被成功解析后,serviceResolved()方法会被回调。当一个服务在网络中被移除时,serviceRemved()会被回调。

JmDNS库在Android平台上效率欠佳

使用NsdManager

自Android 4.1开始实现了一个网络服务的发现服务NsdService,其基于苹果的Bonjour服务发现协议,支持远程服务的发现和零配置。Bonjour协议包括IP地址的自动分配、服务名称与地址的转换以及服务的发现三部分内容,Android 4.1借助第三方开源工程mDNSResponder实现了Bonjour协议的服务名称与地址的转换以及服务的发现等Bonjour部分协议的支持。
NsdManager的使用方法和JmDNS十分相似。

NsdManager nsdManager = (NsdManager) context.getSystemService(Context.NSD_SERVICE)

在这里,注册服务同样是可选的

mNsdManager.registerService(serviceInfo,protocolType,listener);

发现服务是需要指定服务类型、协议类型和一个Listener

mNsdManager.discoverServices(SERVICE_TYPE, NsdManager.PROTOCOL_DNS_SD, listener);

当发现一个新服务时,onServiceFound()方法会被回调,当一个服务丢失或停止提供时,onServiceLost()会被回调。

服务信息解析

当一个服务被发现时,服务的IP地址和端口号仍然是未知的,需要进一步做解析

nsdManager.resolveService(serviceInfo,listener)

如果解析成功,listener的onServiceResolved()会被回调,否则onResolvedFailed()会被回调,失败的原因主要有以下几种:


FAILURE_ALREADY_ACTIVE
出现这个错误表示指定的ServiceInfo已经处于解析状态,一般出现在尝试对一个ServiceInfo进行解析而对应的服务又已经关闭或丢失的情况下,出现此错误后除非重启APP,否则没有其他的恢复手段。 FAILURE_MAX_LIMIT
出现这个错误表示NsdManager能执行的解析任务已经到达上限,可能代表着你多次调用了nsdManager.discoverServices()方法添加了多个lisnenet,经过实验,在Android L上并行解析的上限是10个,要解决这一问题,需要在适当的时候调用nsdManager.stopServiceDiscovery()方法来释放listener。 FAILURE_INTERNAL_ERROR
表示NsdService出现了内部错误

经过服务的发现和解析过程,就可拿到服务对应的IP和Port.


我有一段时间特别想实现一个短距离的手机交互软件,比如多人联机小游戏app或者是多人文件共享app等,思来想去,得出了两个方案,一个是使用手机自带的蓝牙设备,通过蓝牙技术实现两个手机的数据交换,而另一个就是使用socket了。蓝牙技术对于android的小伙伴来说并不陌生,传文件什么的常用到,而且网上资料也十分丰富,所以这里不详细说明。而socket则是网络通信的大神级工具,无论c语言也好j
Android组件化开发(七)--从零开始教你分析项目需求并实现 前面几篇文章我们封装了几个组件化功能组件:包括:**网络请求组件,图片加载请求组件,应用保活组件,音乐播放组件封装。** 每个组件都可以直接拿到自己项目中使用,当然还需根据自己项目要求进行优化。
Android组件化开发(六)-- 短视频播放组件封装 前面几篇文章我们封装了几个组件化功能组件: 包括:`网络请求组件`,`图片加载请求组件`,`应用保活组件`,`音乐播放组件封装`。 每个组件都可以直接拿到自己项目中使用,当然还需根据自己项目要求进行优化。
Android组件化开发(五)--完整版音乐播放组件的封装 前面几篇系列文章我们讲解了`组件化开发`中几个常用功能组件的开发,包括:`网络请求组件`,`图片加载请求组件`,`应用保活组件`。今天我们来封装一个`音乐播放组件`。
Android组件化开发(四)--进程保活组件的封装 前面文章我们封装了网络请求组件`lib_nework`和图片加载组件`lib_image_loader`,今天我们来封装一个进程保活的组件`lib_pull_alive`