在我们的app中添加网络服务发现功能(NSD)以方便在不同的设备上响应局域网中的请求。这种功能对于多设备之间点对点服务来说很有用,例如多人游戏,多人通话,文件共享等。

一,在网络中注册你的服务

注意:这一步是可选操作,如果你对通过局域网广播你的应用服务不关心,这一步大可省去。

在局域网中注册你的服务,首先需要创建一个NsdServiceInfo对象。这个对象封装了局域网内其他设备连接你的服务的信息。

public void registerService(int port){

// Create the NsdServiceInfo object, and populate it.

NsdServiceInfo serviceInfo
= newNsdServiceInfo();



// The name is subject to change based on conflicts

// with other services advertised on the same network.

serviceInfo.setServiceName("NsdChat");

serviceInfo.setServiceType("_http._tcp.");

serviceInfo.setPort(port);

....

}

这个代码片段设置了服务的名称为“NsdChat”。这个名字在网络中是可见的,它使用NSD来搜索局域网内的服务。此外,需要注意的是这个名字在局域网中一定是唯一的,如果冲突的话也不用担心,因为Android会自动处理这种冲突。例如如果在同一个局域网中的两个设备都安装了具备NsdChat服务的应用程序,其中一个应用程序会自动修改服务的名称,如”NsdChat(2)“。

此外这个代码片段也设置了服务的类型,以定义应用程序所使用的传输层和传输协议。具体语法规则中为”_<protocol>._<transportlayer>".在代码片段中使用HTTP协议和TCP传输控制协议。如果一个应用程序提供了打印服务就需要设置服务类型为"_ipp._tcp"。

为了便于集中管理,互联网名称和数字地址分配机构制定了一些权威的服务发现协议标准,其中包括NSD和Bonjour。

在为你的服务设置端口的时候,应该避免与其他应用程序产生冲突。

如果你正在使用套接字,下面的代码片段可以告诉你如何简单地初始化一个套接字 :

public void initializeServerSocket(){

    // Initialize a server socket on the next available port.

    mServerSocket = newServerSocket(0);



    // Store the chosen port.

    mLocalPort =  mServerSocket.getLocalPort();

    ...

}

现在你可以定义一个NsdServiceInfo对象了。此时你需要实现RegistrationListener接口。这个接口包涵了一些回调函数,这些回调函数用来警告你的应用程序是否能够成功注册你的服务,或者告诉你是否能够成功取消注册服务。

public void initializeRegistrationListener(){

mRegistrationListener =
new NsdManager.RegistrationListener(){



@Override

public void onServiceRegistered(NsdServiceInfoNsdServiceInfo){

// Save the service name. Android may have changed it in order to

// resolve a conflict, so update the name you initially requested

// with the name Android actually used.

mServiceName = NsdServiceInfo.getServiceName();

}



@Override

public void onRegistrationFailed(NsdServiceInfo serviceInfo,int
errorCode){

// Registration failed! Put debugging code here to determine why.

}



@Override

public void onServiceUnregistered(NsdServiceInfo arg0){

// Service has been unregistered. This only happens when you call

// NsdManager.unregisterService() and pass in this listener.

}



@Override

public void onUnregistrationFailed(NsdServiceInfo serviceInfo,int
errorCode){

// Unregistration failed. Put debugging code here to determine why.

}

};

}

二,在网络中发现你的服务

在网络中发现我们的服务,就需要我们的应用程序时刻监听网络中可用的服务广播并且进行过滤。服务发现,就像注册服务一样分两步,第一设置一个搜索服务的监听器和与之相关的回调函数,并且创建一个异步的方法discoverServices()。

public void initializeDiscoveryListener(){



// Instantiate a new DiscoveryListener

mDiscoveryListener = newNsdManager.DiscoveryListener(){



// Called as soon as service discovery begins.

@Override

public void onDiscoveryStarted(String regType){

Log.d(TAG,"Service discovery started");

}



@Override

public void onServiceFound(NsdServiceInfo service){

// A service was found! Do something with it.

Log.d(TAG,"Service discovery success"+
service);

if (!service.getServiceType().equals(SERVICE_TYPE)){

// Service type is the string containing the protocol and

// transport layer for this service.

Log.d(TAG,"Unknown Service Type: "+
service.getServiceType());

} elseif(service.getServiceName().equals(mServiceName)){

// The name of the service tells the user what they'd be

// connecting to. It could be "Bob's Chat App".

Log.d(TAG,"Same machine: "+
mServiceName);

} elseif(service.getServiceName().contains("NsdChat")){

mNsdManager.resolveService(service, mResolveListener);

}

}



@Override

public void onServiceLost(NsdServiceInfo service){

// When the network service is no longer available.

// Internal bookkeeping code goes here.

Log.e(TAG,"service lost"+
service);

}



@Override

public void onDiscoveryStopped(String serviceType){

Log.i(TAG,"Discovery stopped: "+
serviceType);

}



@Override

public void onStartDiscoveryFailed(String serviceType,int
errorCode){

Log.e(TAG,"Discovery failed: Error code:"+
errorCode);

mNsdManager.stopServiceDiscovery(this);

}



@Override

public void onStopDiscoveryFailed(String serviceType,int
errorCode){

Log.e(TAG,"Discovery failed: Error code:"+
errorCode);

mNsdManager.stopServiceDiscovery(this);

}

};

}

NSD的API使用这个接口中的回调函数来同志你的应用程序何时开始你的发现服务,合适你的发现服务失败,合适你的发现服务对其他应用程序可见或者不可见。从上面的代码片断中我们可以看到,当你的服务被发现的时候会做出一系列的检查操作:

1.检查搜索到的服务名称是否时自己发出的

2.检查搜索到的服务类型是否是可连接的

3.检查服务名称是否可以被正确的应用程序成功的验证连接。

设置好监听器后,调用discoverServices()方法

mNsdManager.discoverServices(SERVICE_TYPE,NsdManager.PROTOCOL_NSD_SD,mDsicoveryListener);

三,在服务中连接你的服务

当你的应用程序在网络中发现了一个可连接的服务的时候,首先使用resolveService()方法确定可连接服务的信息,实现NsdManager.ResolverListener接口,并且从NsdServiceInfo中得到其中所封装的消息。

public void initializeResolveListener(){

    mResolveListener = newNsdManager.ResolveListener(){



        @Override

        public void onResolveFailed(NsdServiceInfo serviceInfo,int
errorCode){

            // Called when the resolve fails.  Use the error code to debug.

            Log.e(TAG,"Resolve failed"+
errorCode);

        }



        @Override

        public void onServiceResolved(NsdServiceInfo serviceInfo){

            Log.e(TAG,"Resolve Succeeded. "+
serviceInfo);



            if (serviceInfo.getServiceName().equals(mServiceName)){

                Log.d(TAG,"Same IP.");

                return;

            }

            mService = serviceInfo;

            int port = mService.getPort();

            InetAddress host
= mService.getHost();

        }

    };

}

四,应用程序关闭时应取消注册的服务

//In your application's Activity



@Override

protected void onPause(){

if (mNsdHelper!=
null){

mNsdHelper.tearDown();

}

super.onPause();

}



@Override

protected void onResume(){

super.onResume();

if (mNsdHelper!=
null){

mNsdHelper.registerService(mConnection.getLocalPort());

mNsdHelper.discoverServices();

}

}



@Override

protected void onDestroy(){

mNsdHelper.tearDown();

mConnection.tearDown();

super.onDestroy();

}



// NsdHelper's tearDown method

public void tearDown(){

mNsdManager.unregisterService(mRegistrationListener);

mNsdManager.stopServiceDiscovery(mDiscoveryListener);

}

深入学习:如何实现不同Android设备之间相同应用程序的网络服务发现功能的更多相关文章

  1. Android网络服务发现(NSD)协议的使用

    Android的网络服务发现协议(NSD)能够用于在小范围的网络中发现邻近设备上的某个应用.这对于一些社交网络.多人游戏类的应用会很有帮助. Android的NSD的用法大致上分为四种操作: 1. 注 ...

  2. Android设备之间通过Wifi通信

    之前写过PC与Android之间通过WIFI通信(通过Socket,可以在博客里面搜索),PC作为主机,Android作为客户机,现在手头有一台仪器通过wifi传输数据,如果仪器作为主机发射WIFI热 ...

  3. android设备之间屏幕共享

    近期公司在开发一款android的设备把屏幕投射到手机上.同一时候手机还能够触控.键盘操作.这样.就达到了屏幕共享的目的. 思考了一下.主要思路: 1.将截图所获取的位图用ffmpeg编码成视频流. ...

  4. Android(java)学习笔记124:Android权限大全

    访问登记属性 android.permission.ACCESS_CHECKIN_PROPERTIES读取或写入登记check-in数据库属性表的权限 获取错略位置 android.permissio ...

  5. Android(java)学习笔记64:Android权限大全

    访问登记属性 android.permission.ACCESS_CHECKIN_PROPERTIES读取或写入登记check-in数据库属性表的权限 获取错略位置 android.permissio ...

  6. Android Studio快速集成讯飞SDK实现文字朗读功能

    今天,我们来学习一下怎么在Android Studio快速集成讯飞SDK实现文字朗读功能,先看一下效果图: 第一步 :了解TTS语音服务 TTS的全称为Text To Speech,即“从文本到语音” ...

  7. etcd学习(3)-grpc使用etcd做服务发现

    grpc通过etcd实现服务发现 前言 服务注册 服务发现 负载均衡 集中式LB(Proxy Model) 进程内LB(Balancing-aware Client) 独立 LB 进程(Externa ...

  8. 使用Broadcast实现android组件之间的通信 分类: android 学习笔记 2015-07-09 14:16 110人阅读 评论(0) 收藏

    android组件之间的通信有多种实现方式,Broadcast就是其中一种.在activity和fragment之间的通信,broadcast用的更多本文以一个activity为例. 效果如图: 布局 ...

  9. [转] Android应用程序与SurfaceFlinger服务的关系概述和学习计划

    转自:Android应用程序与SurfaceFlinger服务的关系概述和学习计划 SurfaceFlinger服务负责绘制Android应用程序的UI,它的实现相当复杂,要从正面分析它的实现不是一件 ...

随机推荐

  1. python中urllib和urllib2的简单用法

    import urllib #引入urllib模块,这里用urllib2也可以 fpage = urllib.urlopen( url ) #打开网页:例如url=‘http://www.xxx.co ...

  2. IFE 百度前端技术学院 2016年春季班作业 第一阶段任务(1-4)的总结

    具体任务详细介绍可参考http://ife.baidu.com/task/all 具体代码参考:https://github.com/sunshineqt/webxt/tree/master/stag ...

  3. hduoj------2594 Simpsons’ Hidden Talents

    Simpsons’ Hidden Talents Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java ...

  4. js 时间处理

    1.格式化时间 function GetDateTimeFormatter(value) {        if (value == undefined) {            return &q ...

  5. asp.net 使用UrlRewritingNet.UrlRewriter组件URL重写,伪静态详解

    目录 URL重写的业务需求 ReWritingNet组件主要功能 配置IIS(IIS7/8环境下) 程序代码 重写规则 一,URL重写的业务需求 顾客可以直接用浏览器bookmark功能将页面连结储存 ...

  6. java操作字符串,重点是记录一次使用replaceAll对字符串的操作

    符串常用操作(String类) 字符串查找 String提供了两种查找字符串的方法,即indexOf与lastIndexOf方法. 1.indexOf(String s) 该方法用于返回参数字符串s在 ...

  7. syslog简介——系统日志写入API

    一.简介 syslog是Linux系统默认的日志守护进程.默认的主配置文件和辅助配置文件分别是/etc/syslog.conf和/etc/sysconfig/syslog文件.通常,syslog 接受 ...

  8. [转]Web开发的发展史

    之所以转这篇文章是因为它可以对web请求有大致的理解. 以下内容转自:http://www.open-open.com/news/view/19ed96a 英文原文: Full stack web d ...

  9. css改变图片的颜色

    参考大神张鑫旭:http://www.zhangxinxu.com/wordpress/2016/06/png-icon-change-color-by-css/ 主要知识点:border-right ...

  10. Hduacm—5497

    #include <cstring> #include <cstdio> #include <iostream> using namespace std; type ...