在我们的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. robotframework笔记15

    资源和变量文件 用户关键字和变量 测试用例文件 和 测试套件 初始化文件只能用于文件在哪里 了,但 资源文件 提供一种机制来分享它们. 自 资源文件结构非常接近测试用例文件,它是 容易创建它们. 变量 ...

  2. MySQL学习笔记_1_MySQL数据库管理系统概述

    1. MySQL架构 C/S: client / server架构 MySQL DBMS(Data Bank Management System): 数据库管理系统 客户端 <---> 服 ...

  3. HDU-----(1083)Courses(最大匹配)

    Courses Time Limit: 20000/10000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total S ...

  4. PowerDesigner中导出设计说明文档

    点击下图的新建按钮,新建一个导出内容的模板 模板设计界面分为2栏,左边是可选的模板内容,右侧是模板,双击左侧条目会添加到右侧,最后生成的文件中就有此项内容. 已经添加到右侧的内容可以编辑,双击右侧的条 ...

  5. PHP中MySql函数收集

    1.array mysql_fetch_assoc ( resource $result ) 从结果集中取得一行作为关联数组 说明:  返回对应结果集的关联数组,并且继续移动内部数据指针. 参数:re ...

  6. JDE开发端安装笔记

    JDE版本:JD Edwards EnterpriseOne 9.1.4 for Microsoft 64bit Oracle客户端:Oracle Database 11g Release 2 Cli ...

  7. linux系统设置静态IP 查看网卡配置文件

    http://jingyan.baidu.com/article/455a99508be7cda167277865.html vi /etc/sysconfig/network-scripts/ifc ...

  8. FZU 2028 时空门问题

    题目链接:时空门问题 简单bfs,每个格子移动的方式除了上下左右,还有时空门,开始想着用邻接表保存每个点能通过时空门到达的点就ok了.很快的敲出来,很快的WA了.长久的dbug并没有发现error.然 ...

  9. 一模 (2) day1

    第一题: 题目大意: 设 2n 张牌分别标记为 1, 2, ..., n, n+1, ..., 2n,初始时这 2n 张牌按其标号从小到大排列.经一次洗牌后,原来的排列顺序变成 n+1, 1, n+2 ...

  10. sqlite3 SQL常用语句

    1. select SELECT LastName,FirstName FROM Persons; SELECT * FROM Persons; 2. where SELECT * FROM Pers ...