Android局域网通信机制初探

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

  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.

目录
相关文章
|
Android开发 数据安全/隐私保护 开发者
Android实现局域网二维码分享图片(带密码验证)
最近接到一个需求,需要实现一个局域网的图片二维码分享功能;具体怎么样呢?一起看看文章吧!
2710 0
|
Java Android开发
【Android】socket局域网通信
我有一段时间特别想实现一个短距离的手机交互软件,比如多人联机小游戏app或者是多人文件共享app等,思来想去,得出了两个方案,一个是使用手机自带的蓝牙设备,通过蓝牙技术实现两个手机的数据交换,而另一个就是使用socket了。蓝牙技术对于android的小伙伴来说并不陌生,传文件什么的常用到,而且网上资料也十分丰富,所以这里不详细说明。而socket则是网络通信的大神级工具,无论c语言也好j
3428 0
|
网络协议 Shell Android开发
Android模拟器如何设置DNS访问局域网内网站
我们需要用到android-sdk开发包中adb shell指令 见下图   退出adb shell exit
1486 0
|
18天前
|
Java Android开发
Android 开发获取通知栏权限时会出现两个应用图标
Android 开发获取通知栏权限时会出现两个应用图标
12 0
|
1月前
|
XML 缓存 Android开发
Android开发,使用kotlin学习多媒体功能(详细)
Android开发,使用kotlin学习多媒体功能(详细)
91 0
|
1月前
|
设计模式 人工智能 开发工具
安卓应用开发:构建未来移动体验
【2月更文挑战第17天】 随着智能手机的普及和移动互联网技术的不断进步,安卓应用开发已成为一个热门领域。本文将深入探讨安卓平台的应用开发流程、关键技术以及未来发展趋势。通过分析安卓系统的架构、开发工具和框架,本文旨在为开发者提供全面的技术指导,帮助他们构建高效、创新的移动应用,以满足不断变化的市场需求。
18 1
|
1月前
|
机器学习/深度学习 调度 Android开发
安卓应用开发:打造高效通知管理系统
【2月更文挑战第14天】 在移动操作系统中,通知管理是影响用户体验的关键因素之一。本文将探讨如何在安卓平台上构建一个高效的通知管理系统,包括服务、频道和通知的优化策略。我们将讨论最新的安卓开发工具和技术,以及如何通过这些工具提高通知的可见性和用户互动性,同时确保不会对用户造成干扰。
31 1
|
9天前
|
XML 开发工具 Android开发
构建高效的安卓应用:使用Jetpack Compose优化UI开发
【4月更文挑战第7天】 随着Android开发不断进化,开发者面临着提高应用性能与简化UI构建流程的双重挑战。本文将探讨如何使用Jetpack Compose这一现代UI工具包来优化安卓应用的开发流程,并提升用户界面的流畅性与一致性。通过介绍Jetpack Compose的核心概念、与传统方法的区别以及实际集成步骤,我们旨在提供一种高效且可靠的解决方案,以帮助开发者构建响应迅速且用户体验优良的安卓应用。
|
18天前
|
Android开发
Android开发小技巧:怎样在 textview 前面加上一个小图标。
Android开发小技巧:怎样在 textview 前面加上一个小图标。
10 0