Android NSD学习与使用

        在我们的实际开发中,经常会有点对点通讯的需求,我们知道,通讯的基础是知道彼此的标识,在网络中便是IP,如果具体到某一个应用,还需要端口号。那我们的NSD技术其实就是实现在同一wifi的局域网情况下,实现查询设备网络信息(IP和端口)的。NSD的全称是Network Service Discovery。从名称我们也可以看出来其是通过一个服务实现上述功能--Demo源码下载。那我们就来简单看一下其使用流程。关于使用流程,我觉得NSD相关API中NsdManager(系统服务)中的描述可以非常详细和简单的概括了:

/**
 * The Network Service Discovery Manager class provides the API to discover services
 * on a network. As an example, if device A and device B are connected over a Wi-Fi
 * network, a game registered on device A can be discovered by a game on device
 * B. Another example use case is an application discovering printers on the network.
 *
 * 

The API currently supports DNS based service discovery and discovery is currently * limited to a local network over Multicast DNS. DNS service discovery is described at * http://files.dns-sd.org/draft-cheshire-dnsext-dns-sd.txt * *

The API is asynchronous and responses to requests from an application are on listener * callbacks on a seperate internal thread. * *

There are three main operations the API supports - registration, discovery and resolution. *

 *                          Application start
 *                                 |
 *                                 |
 *                                 |                  onServiceRegistered()
 *                     Register any local services  /
 *                      to be advertised with       \
 *                       registerService()            onRegistrationFailed()
 *                                 |
 *                                 |
 *                          discoverServices()
 *                                 |
 *                      Maintain a list to track
 *                        discovered services
 *                                 |
 *                                 |--------->
 *                                 |          |
 *                                 |      onServiceFound()
 *                                 |          |
 *                                 |     add service to list
 *                                 |          |
 *                                 |<----------
 *                                 |
 *                                 |--------->
 *                                 |          |
 *                                 |      onServiceLost()
 *                                 |          |
 *                                 |   remove service from list
 *                                 |          |
 *                                 |<----------
 *                                 |
 *                                 |
 *                                 | Connect to a service
 *                                 | from list ?
 *                                 |
 *                          resolveService()
 *                                 |
 *                         onServiceResolved()
 *                                 |
 *                     Establish connection to service
 *                     with the host and port information
 *
 * 
* An application that needs to advertise itself over a network for other applications to * discover it can do so with a call to {@link #registerService}. If Example is a http based * application that can provide HTML data to peer services, it can register a name "Example" * with service type "_http._tcp". A successful registration is notified with a callback to * {@link RegistrationListener#onServiceRegistered} and a failure to register is notified * over {@link RegistrationListener#onRegistrationFailed} * *

A peer application looking for http services can initiate a discovery for "_http._tcp" * with a call to {@link #discoverServices}. A service found is notified with a callback * to {@link DiscoveryListener#onServiceFound} and a service lost is notified on * {@link DiscoveryListener#onServiceLost}. * *

Once the peer application discovers the "Example" http service, and either needs to read the * attributes of the service or wants to receive data from the "Example" application, it can * initiate a resolve with {@link #resolveService} to resolve the attributes, host, and port * details. A successful resolve is notified on {@link ResolveListener#onServiceResolved} and a * failure is notified on {@link ResolveListener#onResolveFailed}. * * Applications can reserve for a service type at * http://www.iana.org/form/ports-service. Existing services can be found at * http://www.iana.org/assignments/service-names-port-numbers/service-names-port-numbers.xml * * {@see NsdServiceInfo} */

上面是对NsdManager的描述,我觉得看了这个再加上些许整理基本上就掌握了Nsd使用的整体流程。在看之前,我们先做一些说明,首先同一台设备无法实现API功能演示,为了便于理解,我们使用两台设备来说明。一台我们定义为S,另一台定义为C,接着我们来看看上面的描述:

  • (1)NSD主要功能介绍
  • (2)实现机制
  • (3)运行特点(异步,独立线程)
  • (4)实现功能与步骤
  • (5)对于(4)详细解释

上面的五步就是上面的英文的概括,对于其功能我们已经知道了,我们主要关注的如何使用以及具体的实现,所以重点是第4和第5。我们接着来看一下第4部分的内容:

* 

There are three main operations the API supports - registration, discovery and resolution. *

*                          Application start
*                                 |
*                                 |
*                                 |                  onServiceRegistered()
*                     Register any local services  /
*                      to be advertised with       \
*                       registerService()            onRegistrationFailed()
*                                 |
*                                 |
*                          discoverServices()
*                                 |
*                      Maintain a list to track
*                        discovered services
*                                 |
*                                 |--------->
*                                 |          |
*                                 |      onServiceFound()
*                                 |          |
*                                 |     add service to list
*                                 |          |
*                                 |<----------
*                                 |
*                                 |--------->
*                                 |          |
*                                 |      onServiceLost()
*                                 |          |
*                                 |   remove service from list
*                                 |          |
*                                 |<----------
*                                 |
*                                 |
*                                 | Connect to a service
*                                 | from list ?
*                                 |
*                          resolveService()
*                                 |
*                         onServiceResolved()
*                                 |
*                     Establish connection to service
*                     with the host and port information

上面说到这NsdManager主要实现三个功能:

  • 注册(NsdService以及对应的监听NSDServer.IRegisterState)
  • 发现(NsdService)
  • 解析(NsdServiceInfo:里面封装了设备网络的相关信息,host,port等)

具体的使用步骤如下:

  • (1)注册NsdService,初始化注册监听器,成功或者失败会走对应的回调接口
  • (2)发现NsdService,通过初始化设备发现回调接口DiscoveryListener来获取发现设备的信息,通过回调函数onServiceFound实现,同时还可以实时监测丢失的设备,通过onServiceLost实现
  • (3)初始化NsdServiceInfo解析器监听接口,解析发现设备的网络信息,通过回调函数onServiceResolved实现
  • (4)初始化完上述两个接口即可开启扫描 
  • (5)备注:扫描到指定设备并成功获取设备的IP和Port后,即可通过网络API建立连接和通讯。

因为NsdManager既完成了注册服务由完成了发现与解析服务的功能,所以上面的步骤我们还需要分解一下,对于被发现设备S,我们只需要完成第一步即可;对于发现设备C,我们需要实现(2)(3)(4),且最好都在子线程中执行。下面就来看看具体的实现。考虑到实际的应用,我们这里分为服务端和客户端,分别对应于设备S和设备C。我们来看看注册服务的具体实现:

 private void registerService(Context context, String serviceName, int port) {
        mNsdManager = (NsdManager) context.getSystemService(Context.NSD_SERVICE);
        NsdServiceInfo serviceInfo = new NsdServiceInfo();
        serviceInfo.setServiceName(serviceName);
        serviceInfo.setPort(port);
        serviceInfo.setServiceType(mServerType);
        mNsdManager.registerService(serviceInfo, NsdManager.PROTOCOL_DNS_SD, mRegistrationListener);
    }

其中,就是通过NsdManager的registerService来实现,其中的mRegistrationListener的初始化如下:

 //初始化化注册监听器
    private void initializeRegistrationListener() {
        mRegistrationListener = new NsdManager.RegistrationListener() {
            @Override
            public void onRegistrationFailed(NsdServiceInfo serviceInfo, int errorCode) {
                Log.e(TAG, "NsdServiceInfo onRegistrationFailed");
                if (registerState != null) {
                    registerState.onRegistrationFailed(serviceInfo, errorCode);
                }
            }

            @Override
            public void onUnregistrationFailed(NsdServiceInfo serviceInfo, int errorCode) {
                Log.i(TAG, "onUnregistrationFailed serviceInfo: " + serviceInfo + " ,errorCode:" + errorCode);
                if (registerState != null) {
                    registerState.onUnRegistrationFailed(serviceInfo, errorCode);
                }
            }

            @Override
            public void onServiceRegistered(NsdServiceInfo serviceInfo) {
                mServerName = serviceInfo.getServiceName();
                Log.i(TAG, "onServiceRegistered: " + serviceInfo.toString());
                Log.i(TAG, "mServerName onServiceRegistered: " + mServerName);
                if (registerState != null) {
                    registerState.onServiceRegistered(serviceInfo);
                }
            }

            @Override
            public void onServiceUnregistered(NsdServiceInfo serviceInfo) {
                Log.i(TAG, "onServiceUnregistered serviceInfo: " + serviceInfo);
                if (registerState != null) {
                    registerState.onServiceUnregistered(serviceInfo);
                }
            }
        };
    }

上述两步其实就是注册服务的实现了,在实际的应用中结合线程即可完成注册服务的工作,下面就来看看客户端发现并解析服务的实现,首先是初始化发现监听:

  /**
     * 扫描解析前的 NsdServiceInfo
     * 用于服务发现的回调调用接口
     */
    private void initializeDiscoveryListener() {
        mDiscoveryListener = new NsdManager.DiscoveryListener() {
            @Override
            public void onStartDiscoveryFailed(String serviceType, int errorCode) {
                mNsdManager.stopServiceDiscovery(this);
                Log.e(TAG, "onStartDiscoveryFailed():");
            }

            @Override
            public void onStopDiscoveryFailed(String serviceType, int errorCode) {
                mNsdManager.stopServiceDiscovery(this);
                Log.e(TAG, "onStopDiscoveryFailed():");
            }

            @Override
            public void onDiscoveryStarted(String serviceType) {
                Log.e(TAG, "onDiscoveryStarted():");

            }

            @Override
            public void onDiscoveryStopped(String serviceType) {
                Log.e(TAG, "onDiscoveryStopped():");
            }

            /**
             *
             * @param serviceInfo
             */
            @Override
            public void onServiceFound(NsdServiceInfo serviceInfo) {
                Log.e(TAG, "onServiceFound: "+serviceInfo );
                discoveryList.add(serviceInfo.toString());
                //根据咱服务器的定义名称,指定解析该 NsdServiceInfo
                if (serviceInfo.getServiceName().equals(mServiceName)) {
                    mNsdManager.resolveService(serviceInfo, mResolverListener);
                }
            }

            @Override
            public void onServiceLost(NsdServiceInfo serviceInfo) {
                Log.e(TAG, "onServiceLost(): serviceInfo=" + serviceInfo);
                discoveryList.remove(serviceInfo.toString());
            }
        };
    }

初始化解析器监听器:

/**
     * 解析发现的NsdServiceInfo
     */
    private void initializeResolveListener() {
        mResolverListener = new NsdManager.ResolveListener() {
            @Override
            public void onResolveFailed(NsdServiceInfo serviceInfo, int errorCode) {

            }

            @Override
            public void onServiceResolved(NsdServiceInfo serviceInfo) {
                int port = serviceInfo.getPort();
                String serviceName = serviceInfo.getServiceName();
                String hostAddress = serviceInfo.getHost().getHostAddress();

                Message message=Message.obtain();
                message.what=1;
                message.obj=serviceInfo.toString();
                mHandler.sendMessage(message);

                Log.e(TAG, "onServiceResolved 已解析:" + " host:" + hostAddress + ":" + port + " ----- serviceName: " + serviceName);
                resolveList.add(" host:" + hostAddress + ":" + port );
                //TODO 建立网络连接

            }
        };
    }

开始扫描:

 public void startNSDClient(Handler handler) {
        mHandler=handler;
        mNsdManager = (NsdManager) mContext.getSystemService(Context.NSD_SERVICE);
        initializeDiscoveryListener();//初始化监听器
        initializeResolveListener();//初始化解析器
        mNsdManager.discoverServices(NSD_SERVER_TYPE, NsdManager.PROTOCOL_DNS_SD, mDiscoveryListener);//开启扫描

    }

上面只是一个流程,没有形成一个完整的示例,下面我就结合上面的介绍给出一个完整的示例代码功能,示例中由服务端和客户端组成,服务端有以下功能:

  • 完整NsdService注册
  • 更改NsdService注册的名称
  • 取消注册

客户端主要有以下功能:

  • 发现并解析服务端的网络信息
  • 设置发现NsdService的名称
  • 显示发现的服务网络信息

 

服务端代码:

NsdServer.java:

package aoto.com.operationnsd;

import android.content.Context;
import android.net.nsd.NsdManager;
import android.net.nsd.NsdServiceInfo;
import android.util.Log;


/**
 * @author why
 * @date 2019.04.28
 */

public class NSDServer {
    public static final String TAG = "NSDServerWhy";
    private NsdManager mNsdManager;
    private NsdManager.RegistrationListener mRegistrationListener;
    private IRegisterState registerState; //NSD服务接口对象
    private String mServerName;
    private final String mServerType = "_http._tcp.";  // 服务器type,要客户端扫描服务器的一致

    public NSDServer() {
    }

    public void startNSDServer(Context context, String serviceName, int port) {
        initializeRegistrationListener();
        registerService(context, serviceName, port);
    }

    //初始化化注册监听器
    private void initializeRegistrationListener() {
        mRegistrationListener = new NsdManager.RegistrationListener() {
            @Override
            public void onRegistrationFailed(NsdServiceInfo serviceInfo, int errorCode) {
                Log.e(TAG, "NsdServiceInfo onRegistrationFailed");
                if (registerState != null) {
                    registerState.onRegistrationFailed(serviceInfo, errorCode);
                }
            }

            @Override
            public void onUnregistrationFailed(NsdServiceInfo serviceInfo, int errorCode) {
                Log.i(TAG, "onUnregistrationFailed serviceInfo: " + serviceInfo + " ,errorCode:" + errorCode);
                if (registerState != null) {
                    registerState.onUnRegistrationFailed(serviceInfo, errorCode);
                }
            }

            @Override
            public void onServiceRegistered(NsdServiceInfo serviceInfo) {
                mServerName = serviceInfo.getServiceName();
                Log.i(TAG, "onServiceRegistered: " + serviceInfo.toString());
                Log.i(TAG, "mServerName onServiceRegistered: " + mServerName);
                if (registerState != null) {
                    registerState.onServiceRegistered(serviceInfo);
                }
            }

            @Override
            public void onServiceUnregistered(NsdServiceInfo serviceInfo) {
                Log.i(TAG, "onServiceUnregistered serviceInfo: " + serviceInfo);
                if (registerState != null) {
                    registerState.onServiceUnregistered(serviceInfo);
                }
            }
        };
    }

    private void registerService(Context context, String serviceName, int port) {
        mNsdManager = (NsdManager) context.getSystemService(Context.NSD_SERVICE);
        NsdServiceInfo serviceInfo = new NsdServiceInfo();
        serviceInfo.setServiceName(serviceName);
        serviceInfo.setPort(port);
        serviceInfo.setServiceType(mServerType);
        mNsdManager.registerService(serviceInfo, NsdManager.PROTOCOL_DNS_SD, mRegistrationListener);
    }

    public void stopNSDServer() {
        mNsdManager.unregisterService(mRegistrationListener);
    }


    //NSD服务注册监听接口
    public interface IRegisterState {
        void onServiceRegistered(NsdServiceInfo serviceInfo);     //注册NSD成功

        void onRegistrationFailed(NsdServiceInfo serviceInfo, int errorCode);   //注册NSD失败

        void onServiceUnregistered(NsdServiceInfo serviceInfo);  //取消NSD注册成功

        void onUnRegistrationFailed(NsdServiceInfo serviceInfo, int errorCode); //取消NSD注册失败

    }


    //设置NSD服务接口对象
    public void setRegisterState(IRegisterState registerState) {
        this.registerState = registerState;
    }
}

独立线程处理注册任务

package aoto.com.operationnsd;

import android.content.Context;
import android.net.nsd.NsdServiceInfo;
import android.util.Log;


/**
 * author:why
 * created on: 2019/3/4 15:11
 * description:
 */
public class NsdServerRunnable implements Runnable {

    private static final String TAG = "NsdServerRunnableWhy";
    /**
     * 注册 NSD 服务的名称 和 端口 这个可以设置默认固定址,用于客户端通过 NSD_SERVER_NAME 筛选得到服务端地址和端口
     */
    private String nsdServerName ;
    private final int NSD_PORT = 8088;
    private NSDServer nsdServer;
    private Context context;

    public NsdServerRunnable(String nsdServerName, NSDServer nsdServer, Context context){
        this.nsdServerName=nsdServerName;
        this.nsdServer=nsdServer;
        this.context=context;
    }

    @Override
    public void run() {

        nsdServer.startNSDServer(context, nsdServerName, NSD_PORT);
        nsdServer.setRegisterState(new NSDServer.IRegisterState() {
            @Override
            public void onServiceRegistered(NsdServiceInfo serviceInfo) {
                Log.e(TAG, "onServiceRegistered: " + serviceInfo.toString());
                //已经注册可停止该服务
//                    nsdServer.stopNSDServer();
            }
            @Override
            public void onRegistrationFailed(NsdServiceInfo serviceInfo, int errorCode) {

            }
            @Override
            public void onServiceUnregistered(NsdServiceInfo serviceInfo) {

            }
            @Override
            public void onUnRegistrationFailed(NsdServiceInfo serviceInfo, int errorCode) {

            }
        });
    }
}

对外接口管理类:

package aoto.com.operationnsd;

import android.content.Context;
import android.util.Log;


/**
 * author:why
 * created on: 2019/3/4 15:15
 * description:
 */
public class NsdServerManager {
    private static final String TAG = "NsdServerManagerWhy";
    private volatile  static NsdServerManager nsdServerManager;
    private static NSDServer nsdServer;
    private Context context;

    public NsdServerManager(Context context){
        this.context=context;
    }

    public static NsdServerManager getInstance(Context context){
        if(nsdServerManager==null){
            synchronized (NsdServerManager.class){
                if (nsdServerManager==null) {
                    nsdServer=new NSDServer();
                    nsdServerManager = new NsdServerManager(context);
                }
            }
        }
        return nsdServerManager;
    }

    /**
     * 注册Nsd服务
     * @param nsdServerName
     */
    public void registerNsdServer(String nsdServerName) {
        new Thread(new NsdServerRunnable(nsdServerName,nsdServer,context)).start();
    }
    
    /**
     * 取消注册NsdServer
     */
    public void unRegisterNsdServer(){
        Log.e(TAG, "unRegisterNsdServer: " );
        nsdServer.stopNSDServer();
    }


}

调用代码:

package aoto.com.operationnsd;


import android.Manifest;
import android.net.nsd.NsdServiceInfo;
import android.os.Build;
import android.os.Bundle;
import android.support.annotation.RequiresApi;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import android.widget.EditText;
import android.widget.TextView;


/**
 * 无论两端哪边先结束应用再打开 Netty 都可以 可实现断线重连
 */
public class MainActivity extends AppCompatActivity {

    private static final String TAG = "ServerWhy";

    TextView clientMessage;
    TextView serverTitle;
    EditText newNsdServerView;
    NsdServerManager nsdServerManager;

    /**
     * 注册 NSD 服务的名称 和 端口 这个可以设置默认固定址,用于客户端通过 NSD_SERVER_NAME 筛选得到服务端地址和端口
     */
    private String nsd_server_name = "WhySystem";
    private int nsd_server_port = 8088;

    @RequiresApi(api = Build.VERSION_CODES.M)
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initUI();

        nsdServerManager = NsdServerManager.getInstance(this);
        nsdServerManager.registerNsdServer(nsd_server_name);
    }


    private void initUI() {
        clientMessage = findViewById(R.id.message_from_client);
        serverTitle = findViewById(R.id.server_title);
        serverTitle.append("----" + nsd_server_name);
        newNsdServerView = findViewById(R.id.nsd_server_name);
    }


    /**
     * 重置NSD服务器名称
     *
     * @param view
     */
    public void resetServerName(View view) {
        nsd_server_name = newNsdServerView.getText().toString();
        serverTitle.setText("Nsd 服务端----" + nsd_server_name);
        nsdServerManager.registerNsdServer(nsd_server_name);
    }

    public void unRegister(View view) {
        nsdServerManager.unRegisterNsdServer();
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        nsdServerManager.unRegisterNsdServer();
    }
}

 

客户端代码如下:

package aoto.com.nsdclient;


import android.content.Context;
import android.net.nsd.NsdManager;
import android.net.nsd.NsdServiceInfo;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import java.util.ArrayList;


/**
 * @author why
 * @date 2019.04.28
 */
public class NsdClient {

    public static final String TAG = "NsdClientWhy";

    private final String NSD_SERVER_TYPE = "_http._tcp.";
    private NsdManager.DiscoveryListener mDiscoveryListener;
    private NsdManager.ResolveListener mResolverListener;
    public NsdManager mNsdManager;
    private Context mContext;
    private String mServiceName;
    private Handler mHandler;
    private IServerFound mIServerFound;
    private ArrayList discoveryList=new ArrayList<>();
    private ArrayList resolveList=new ArrayList<>();

    /**
     * @param context:上下文对象
     * @param serviceName  客户端扫描 指定的地址
     * @param iServerFound 回调
     */
    public NsdClient(Context context, String serviceName, IServerFound iServerFound) {
        mContext = context;
        mServiceName = serviceName;
        mIServerFound = iServerFound;
    }

    public void startNSDClient(final Handler handler) {

        new Thread(){
            @Override
            public void run() {
                mHandler=handler;
                mNsdManager = (NsdManager) mContext.getSystemService(Context.NSD_SERVICE);
                initializeDiscoveryListener();//初始化监听器
                initializeResolveListener();//初始化解析器
                mNsdManager.discoverServices(NSD_SERVER_TYPE, NsdManager.PROTOCOL_DNS_SD, mDiscoveryListener);//开启扫描
            }
        }.start();
    }

    /**
     * 扫描解析前的 NsdServiceInfo
     */
    private void initializeDiscoveryListener() {
        mDiscoveryListener = new NsdManager.DiscoveryListener() {
            @Override
            public void onStartDiscoveryFailed(String serviceType, int errorCode) {
                mNsdManager.stopServiceDiscovery(this);
                Log.e(TAG, "onStartDiscoveryFailed():");
            }

            @Override
            public void onStopDiscoveryFailed(String serviceType, int errorCode) {
                mNsdManager.stopServiceDiscovery(this);
                Log.e(TAG, "onStopDiscoveryFailed():");
            }

            @Override
            public void onDiscoveryStarted(String serviceType) {
                Log.e(TAG, "onDiscoveryStarted():");

            }

            @Override
            public void onDiscoveryStopped(String serviceType) {
                Log.e(TAG, "onDiscoveryStopped():");
            }

            /**
             *
             * @param serviceInfo
             */
            @Override
            public void onServiceFound(NsdServiceInfo serviceInfo) {
                Log.e(TAG, "onServiceFound: "+serviceInfo );
                discoveryList.add(serviceInfo.toString());
                //根据咱服务器的定义名称,指定解析该 NsdServiceInfo
                if (serviceInfo.getServiceName().equals(mServiceName)) {
                    mNsdManager.resolveService(serviceInfo, mResolverListener);
                }
            }

            @Override
            public void onServiceLost(NsdServiceInfo serviceInfo) {
                Log.e(TAG, "onServiceLost(): serviceInfo=" + serviceInfo);
                discoveryList.remove(serviceInfo.toString());
            }
        };
    }

    /**
     * 解析发现的NsdServiceInfo
     */
    private void initializeResolveListener() {
        mResolverListener = new NsdManager.ResolveListener() {
            @Override
            public void onResolveFailed(NsdServiceInfo serviceInfo, int errorCode) {

            }

            @Override
            public void onServiceResolved(NsdServiceInfo serviceInfo) {
                int port = serviceInfo.getPort();
                String serviceName = serviceInfo.getServiceName();
                String hostAddress = serviceInfo.getHost().getHostAddress();

                Message message=Message.obtain();
                message.what=1;
                message.obj=serviceInfo.toString();
                mHandler.sendMessage(message);

                Log.e(TAG, "onServiceResolved 已解析:" + " host:" + hostAddress + ":" + port + " ----- serviceName: " + serviceName);
                resolveList.add(" host:" + hostAddress + ":" + port );
                //TODO 建立网络连接

            }
        };
    }

    public void stopNSDServer() {
        mNsdManager.stopServiceDiscovery(mDiscoveryListener);
    }

    public interface IServerFound {

        /**
         * 回調 指定解析的结果
         */
        void onServerFound(NsdServiceInfo serviceInfo, int port);

        /**
         * 無合適 回調失敗
         */
        void onServerFail();
    }
}

对外接口管理类:

package aoto.com.nsdclient;

import android.content.Context;
import android.net.nsd.NsdServiceInfo;
import android.os.Handler;
import android.os.Message;
import android.util.Log;

/**
 * author:why
 * created on: 2019/4/28 15:17
 * description:
 */
public class NsdClientManager {

    private static final String TAG = "NsdClientManagerWhy";
    /**
     * Nsd 客户端搜索
     */
    private NsdClient nsdClient;
    private Context context;
    private Handler mHandler;
    private volatile static NsdClientManager mNsdClientManager=null;

    private NsdClientManager(Context context,Handler handler){
        this.context=context;
        this.mHandler=handler;
    }

    /**
     * DCL Single Instance
     * @param context
     * @param handler
     * @return
     */
    public static NsdClientManager getInstance(Context context,Handler handler){
       if(mNsdClientManager==null){
           synchronized (NsdClientManager.class){
               if(mNsdClientManager==null){
                   mNsdClientManager=new NsdClientManager(context,handler);
               }
           }
       }
       return mNsdClientManager;
    }

    /**
     * 通过Nsd 搜索注册过的服务器相关参数进行Socket连接(IP和Port)
     */
    public void searchNsdServer(final String nsdServerName) {
        nsdClient = new NsdClient(context, nsdServerName, new NsdClient.IServerFound() {
            @Override
            public void onServerFound(NsdServiceInfo info, int port) {
                if (info != null) {
                    Log.e(TAG, "onServerFound: "+info.toString() );
                    if (info.getServiceName().equals(nsdServerName)) {
                        //扫描到指定的server停止扫描
                        nsdClient.stopNSDServer();
                    }
                }
            }

            @Override
            public void onServerFail() {

            }
        });

        nsdClient.startNSDClient(mHandler);
    }
}

上面就是逻辑的主要代码,在我们获取到服务端的IP和Port之后,就可以通过网络技术进行连接和通讯了。需要注意的是,上面的搜索NsdService的时候,都是搜索特定名称的,对于服务丢失我也没有在客户端界面做相应的处理,这个可以根据具体的需求来设置和处理。此外,在测试的时候一定要处于同一网络下且不要忘了网络权限哟。结果不便于展示,可以自己下载源码测试调优。

注:欢迎扫码关注

 

 

你可能感兴趣的:(Android基础,随笔)