这些日子碰到这样一个需求,需要在局域网中发现我们创建的某个特定设备,并连上互相通信。本以为要去遍历整个局域网,后来查阅相关资料后发现 Android 为我们提供了网络服务发现(Network Service Discovery)简称 NSD,就是本文要讲的东西了。
NSD 有什么用
用来扫描局域网中特定的服务,并与之通信。省去了自己去写发现协议。
NSD 怎么用
创建服务
首先要创建一个 ServerSocket,用来等待别人的连接
1
2
3
4
5
6
7
8
9
10
11
12
|
/**
*创建一个 server 来获取端口
*/
private void createServerSocket() {
if (mServerSocket != null) return;
try {
mServerSocket = new ServerSocket(0);//设为 0,会自动获取没有占用的端口
mPort = mServerSocket.getLocalPort();
} catch (IOException e) {
e.printStackTrace();
}
}
|
接下来就可以创建 NsdServiceInfo 了,NsdServiceInfo 是一个包含 Nsd 服务信息的类,看名字就知道了。
1
2
3
4
5
6
7
8
9
10
|
/**
*创建 NsdServiceInfo
*/
private void createNsdServiceInfo() {
if (mNsdServiceInfo != null) return;
mNsdServiceInfo = new NsdServiceInfo();
mNsdServiceInfo.setServiceName(SERVICE_NAME);//设置服务的名字,被别的机器发现时显示的名字。
mNsdServiceInfo.setServiceType(SERVICE_TYPE);
mNsdServiceInfo.setPort(mPort);
}
|
注册 NSD 服务
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
private void register() {
mNsdManager = (NsdManager) getSystemService(NSD_SERVICE);
mNsdManager.registerService(mNsdServiceInfo, NsdManager.PROTOCOL_DNS_SD,mRegistrationListener);
}
private void createRegistration() {
mRegistrationListener = new NsdManager.RegistrationListener() {
@Override
public void onRegistrationFailed(NsdServiceInfo nsdServiceInfo, int i){
Toast.makeText(MainActivity.this, "onRegistrationFailed", Toast.LENGTH_SHORT).show();
}
@Override
public void onUnregistrationFailed(NsdServiceInfo nsdServiceInfo, int i) {
Toast.makeText(MainActivity.this, "onUnregistrationFailed", Toast.LENGTH_SHORT).show();
}
@Override
public void onServiceRegistered(NsdServiceInfo nsdServiceInfo) {
Toast.makeText(MainActivity.this, "onServiceRegistered", Toast.LENGTH_SHORT).show();
new Thread(MainActivity.this).start();
}
@Override
public void onServiceUnregistered(NsdServiceInfo nsdServiceInfo) {
Toast.makeText(MainActivity.this, "onServiceUnregistered", Toast.LENGTH_SHORT).show();
}
};
}
|
在客户端发现 NSD 服务
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
|
nsdManager.discoverServices(SERVICE_TYPE, NsdManager.PROTOCOL_DNS_SD, mDiscoveryListener);
private void createDiscoverListener() {
mDiscoveryListener = new NsdManager.DiscoveryListener() {
@Override
public void onStartDiscoveryFailed(String s, int i) {
Toast.makeText(MainActivity.this, "onStartDiscoveryFailed", Toast.LENGTH_SHORT).show();
}
@Override
public void onStopDiscoveryFailed(String s, int i) {
Toast.makeText(MainActivity.this, "onStopDiscoveryFailed", Toast.LENGTH_SHORT).show();
}
@Override
public void onDiscoveryStarted(String s) {
Toast.makeText(MainActivity.this, "onDiscoveryStarted", Toast.LENGTH_SHORT).show();
}
@Override
public void onDiscoveryStopped(String s) {
Toast.makeText(MainActivity.this, "onDiscoveryStopped", Toast.LENGTH_SHORT).show();
}
@Override
public void onServiceFound(NsdServiceInfo nsdServiceInfo) {
//这里的 nsdServiceInfo 只能获取到名字,ip 和端口都不能获取到,要想获取到需要调用 NsdManager.resolveService 方法
datas.add(nsdServiceInfo);
mHandler.sendEmptyMessage(0);
}
@Override
public void onServiceLost(NsdServiceInfo nsdServiceInfo) {
Toast.makeText(MainActivity.this, "onServiceLost", Toast.LENGTH_SHORT).show();
}
};
}
|
获取服务的详细信息
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
nsdManager.resolveService(nsdServiceInfo, mResolverListener);
private void createResolverListener() {
mResolverListener = new NsdManager.ResolveListener() {
@Override
public void onResolveFailed(NsdServiceInfo nsdServiceInfo, int i) {
Toast.makeText(MainActivity.this, "onResolveFailed", Toast.LENGTH_SHORT).show();
}
@Override
public void onServiceResolved(NsdServiceInfo nsdServiceInfo) {
mNsdServiceInfo = nsdServiceInfo;
new Thread(MainActivity.this).start();
}
};
}
|
连接
1
2
3
4
|
mSocket = new Socket(mNsdServiceInfo.getHost().getHostAddress(), mNsdServiceInfo.getPort());
bufferedWriter = new BufferedWriter(new OutputStreamWriter(mSocket.getOutputStream()));
bufferedWriter.write("我连上你了!" + "\n");
bufferedWriter.flush();
|
效果图
NSD
相关资料链接