Android局域网通信机制初探

简介

在网络上,两台主机要进行通信,就必须互相知晓对方的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()会被回调,失败的原因主要有以下几种:

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

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

时间: 2024-08-29 01:28:20

Android局域网通信机制初探的相关文章

android局域网通信-android局域网即时通信

问题描述 android局域网即时通信 问大家个问题啊 组播multicasesocket audiorecord以及audiotrack我都做过一些小程序 但是现在想做个局域网的聊天 功能有音频传输(像微信那样的)和信息传输 我该怎么做呢? 解决方案 首先要有个服务器,可以通过笔记本来架设手机端用过访问固定Ip:port来传输信息

Android AIDL——进程通信机制详解_Android

Android  AIDL, Android进程机制通信机制,这里就整理下AIDL 的知识,帮助大家学习理解此部分知识! 什么是 AIDL AIDL 全称 Android Interface Definition Language,即 安卓接口描述语言.听起来很深奥,其实它的本质就是生成进程间通信接口的辅助工具.它的存在形式是一种 .aidl 文件,开发者需要做的就是在该文件中定义进程间通信的接口,编译的时候 IDE 就会根据我们的 .aidl 接口文件生成可供项目使用的 .java 文件,这和

Android AIDL——进程通信机制详解

Android  AIDL, Android进程机制通信机制,这里就整理下AIDL 的知识,帮助大家学习理解此部分知识! 什么是 AIDL AIDL 全称 Android Interface Definition Language,即 安卓接口描述语言.听起来很深奥,其实它的本质就是生成进程间通信接口的辅助工具.它的存在形式是一种 .aidl 文件,开发者需要做的就是在该文件中定义进程间通信的接口,编译的时候 IDE 就会根据我们的 .aidl 接口文件生成可供项目使用的 .java 文件,这和

深入理解Android组件间通信机制对面向对象特性的影响详解_Android

组件的特点对于Android的四大组件Activity, Service, ContentProvider和Service,不能有Setter和Getter,也不能给组件添加接口.原因是组件都是给系统框架调用的,开发者只能实现其规定的回调接口,组件的创建与销毁都是由系统框架控制的,开发者不能强行干预,更没有办法获取组件的对象.比如Activity,Service,BroadcastReceiver,你没有办法去创建一个Activity,Service或BroadcastReceiver,然后像使

局域网-Android socket通信出现Java.net.ConnectException

问题描述 Android socket通信出现Java.net.ConnectException 服务器和安卓都是用一个wifi,局域网内,service后台访问一段时间后会出现这个情况. 当把手机改为流量上网后,可以一直接收信息,不会出现图片情况.请教大神...急等! 解决方案 确实服务器的地址就是60.10.57.52?外网能访问,大半还是ip的问题. 解决方案二: 怀疑是服务端的问题,出现这种情况后,看看服务端端口是不是打开的

android IPC之binder通信机制_Android

Binder通信机制说来简单,但是在使用的过程的遇到了一些问题,最后终于解决了,在这总结一下,一并分享给大家: 1.要使用Binder通信,首先要定义接口,然后实现服务端BnInterface***和客户端BpInterface***,说到底一个是把参数解包,一个是把参数打包. 2.服务端要能够接收Binder调用请求,要具备两个条件:一个是实现Bn接口,另一个是调用IPCProcess()->self->startThreadPool() IPCThread()->Self->j

理解Android系统Binder机制_Android

一.Binder机制概述 在Android开发中,很多时候我们需要用到进程间通信,所谓进程间通信,实现进程间通信的机制有很多种,比如说socket.pipe等,Android中进程间通信的方式主要有三种: 1.标准Linux Kernel IPC 接口: 2.标准D-BUS接口: 3.Binder接口. 其中,Binder机制是使用最且最被认可的,因为Binder机制有以下优点: 1.相对于其它IPC机制,Binder机制更加简洁和快速: 2.消耗的内存相对更少: 3.传统的IPC机制可能会增加

mpich 通信-MPICH2通信机制是什么

问题描述 MPICH2通信机制是什么 在查找了很多关于MPICH的资料,始终不了解MPICH2的通信机制,请教大神们它的通信机制是如何的,我们都知其在局域网可以做到,那么在广域网能否做到,是如何实现的?

Android中Handler机制问题

问题描述 Android中Handler机制问题 android中我们常通过handler来进行线程间的通信,里面通过Looper来进行消息管理.线程间的通信都可以自己来实现,Handler的优势在哪线程间通信 解决方案 Android中的Handler机制(一)android handler机制Android Handler机制 解决方案二: 最大优势是,Handler运行在主线程中(UI线程中),可以让子线程通过handler更新UI操作 解决方案三: handler主要优势就是线程通讯呀,