在我们的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. hibernate执行sql的三种方式

    方式一:直接使用HibernateTemplate的find()方法,find方法支持执行hql语句 List<T> list = this.getHibernateTemplate(). ...

  2. EM算法原理以及高斯混合模型实践

    EM算法有很多的应用: 最广泛的就是GMM混合高斯模型.聚类.HMM等等. The EM Algorithm 高斯混合模型(Mixtures of Gaussians)和EM算法 EM算法 求最大似然 ...

  3. hduoj-----(2896)病毒侵袭(ac自动机)

    病毒侵袭 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submis ...

  4. javaSE基础——常见的dos命令即其他

     常用的DOS命令 dir(directory) :    列出当前目录下的文件以及文件夹 md(make directory) : 创建目录 rd(remove directory) : 删除目录 ...

  5. 使用BTRACE定位系统中慢的问题

    在访问页面请求的时候,如果系统执行效率低,我们怎样才能定位到这些页面请求呢?   java 有一个十分有效的动态跟踪工具-btrace 网址:https://kenai.com/projects/bt ...

  6. linux 设置windows共享

    在linux下需要设置windows共享. 我们使用SMBA来实现. 1.查看是否安装smba. rpm -qa | grep samba 如果没有安装,则去 www.rpmfind.net 下载sm ...

  7. UVALive 6948 Jokewithpermutation dfs

    题目链接:UVALive 6948  Jokewithpermutation 题意:给一串数字序列,没有空格,拆成从1到N的连续数列. dfs. 可以计算出N的值,也可以直接检验当前数组是否合法. # ...

  8. [示例]NSPredicate基础-查询数组中负荷条件的子集

    代码: #import <Foundation/Foundation.h> int main(int argc, const char * argv[]) { @autoreleasepo ...

  9. C# 定时器事件(设置时间间隔,间歇性执行某一函数,控制台程序)

    定时器事件代码 static void Main(string[] args) { Method(); #region 定时器事件 Timer aTimer = new Timer(); aTimer ...

  10. POJ 3274 Gold Balanced Lineup 哈希,查重 难度:3

    Farmer John's N cows (1 ≤ N ≤ 100,000) share many similarities. In fact, FJ has been able to narrow ...