在我们的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. jmeter 构建一个数据库测试计划

    添加用户 第一步你想做的每一个JMeter测试计划是添加一个 线程组 元素. 的线程组 告诉JMeter的用户数量你想模拟,用户应该多长时间 发送请求,他们应该发送的请求的数量. 继续添加Thread ...

  2. ubuntu下python3安装类库

    ubuntu是默认安装了python2的,所以直接使用 pip install XXX 是默认安装到python2的,安装到python3 的指令是 pip3 install XXXX 或者 pyth ...

  3. HTML5自学笔记[ 21 ]canvas绘图实例之马赛克

    <!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8&quo ...

  4. 杂谈:Servlet(2)

    Servlet的方法剖析: 1.service()方法里面做了什么? 2.doGet()与doPost()做了什么?应该怎么写? 回答 1.service()方法里面做了什么? 如果你的service ...

  5. 转:怎样在VMware ESXi上 克隆虚拟机

    Cloning virtual machines on VMware ESXi 翻译自http://www.dedoimedo.com/computers/vmware-esxi-clone-mach ...

  6. @media用法。

    @media版本:CSS2  兼容性:IE5+   语法:    @media  sMedia { sRules }    说明:    sMedia :  指定设备名称.请参阅附录:设备类型  sR ...

  7. 从java 转到 c# 知识点

    1. 重写的父类方法 必须是虚方法 用virtual 关键字修饰 而子类必须用 ovrride 关键字 java中不需要,, 2. namespace => packet using => ...

  8. chkconfig命令

    chkconfig --list                  #列出系统所有的服务启动情况chkconfig --add xxx           #增加xxx服务chkconfig --de ...

  9. spring 标注

    1.添加支持标注的spring中的jar包: spring-context.jar spring-context-support.jar 2.在xml中配置命名空间和schema <beans ...

  10. 喜讯!Ubuntu 16.10(Yakkety Yak) Final Beta发布喽!!!

    上月三十日,代号为"Yakkety Yak"的Ubuntu 16.10发行版本的Final Beta正式上线.Canonical的开发者Steve Langasek说道:" ...