Using Network Service Discovery 使用网络服务搜索

来源:互联网 发布:怎样应对大数据时代 编辑:程序博客网 时间:2024/06/04 18:48

Adding Network Service Discovery (NSD) to your app allows your users to identify other devices on the local network that support the services your app requests. This is useful for a variety of peer-to-peer applications such as file sharing or multi-player gaming. Android's NSD APIs simplify the effort required for you to implement such features. http://blog.csdn.net/sergeycao

This lesson shows you how to build an application that can broadcast its name and connection information to the local network and scan for information from other applications doing the same. Finally, this lesson shows you how to connect to the same application running on another device.

Register Your Service on the Network

Note: This step is optional. If you don't care about broadcasting your app's services over the local network, you can skip forward to the next section,Discover Services on the Network.

To register your service on the local network, first create a NsdServiceInfo object. This object provides the information that other devices on the network use when they're deciding whether to connect to your service.

public void registerService(int port) {    // Create the NsdServiceInfo object, and populate it.    NsdServiceInfo serviceInfo  = new NsdServiceInfo();    // 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);    ....}

This code snippet sets the service name to "NsdChat". The name is visible to any device on the network that is using NSD to look for local services. Keep in mind that the name must be unique for any service on the network, and Android automatically handles conflict resolution. If two devices on the network both have the NsdChat application installed, one of them changes the service name automatically, to something like "NsdChat (1)".

The second parameter sets the service type, specifies which protocol and transport layer the application uses. The syntax is "_<protocol>._<transportlayer>". In the code snippet, the service uses HTTP protocol running over TCP. An application offering a printer service (for instance, a network printer) would set the service type to "_ipp._tcp".

Note: The International Assigned Numbers Authority (IANA) manages a centralized, authoritative list of service types used by service discovery protocols such as NSD and Bonjour. You can download the list fromthe IANA list of service names and port numbers. If you intend to use a new service type, you should reserve it by filling out theIANA Ports and Service registration form.

When setting the port for your service, avoid hardcoding it as this conflicts with other applications. For instance, assuming that your application always uses port 1337 puts it in potential conflict with other installed applications that use the same port. Instead, use the device's next available port. Because this information is provided to other apps by a service broadcast, there's no need for the port your application uses to be known by other applications at compile-time. Instead, the applications can get this information from your service broadcast, right before connecting to your service.

If you're working with sockets, here's how you can initialize a socket to any available port simply by setting it to 0.

public void initializeServerSocket() {    // Initialize a server socket on the next available port.    mServerSocket = new ServerSocket(0);    // Store the chosen port.    mLocalPort =  mServerSocket.getLocalPort();    ...}

Now that you've defined the NsdServiceInfo object, you need to implement theRegistrationListener interface. This interface contains callbacks used by Android to alert your application of the success or failure of service registration and unregistration.

public void initializeRegistrationListener() {    mRegistrationListener = new NsdManager.RegistrationListener() {        @Override        public void onServiceRegistered(NsdServiceInfo NsdServiceInfo) {            // 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.        }    };}

Now you have all the pieces to register your service. Call the method registerService().

Note that this method is asynchronous, so any code that needs to run after the service has been registered must go in theonServiceRegistered() method.

public void registerService(int port) {    NsdServiceInfo serviceInfo  = new NsdServiceInfo();    serviceInfo.setServiceName("NsdChat");    serviceInfo.setServiceType("_http._tcp.");    serviceInfo.setPort(port);    mNsdManager = Context.getSystemService(Context.NSD_SERVICE);    mNsdManager.registerService(            serviceInfo, NsdManager.PROTOCOL_DNS_SD, mRegistrationListener);}

Discover Services on the Network

The network is teeming with life, from the beastly network printers to the docile network webcams, to the brutal, fiery battles of nearby tic-tac-toe players. The key to letting your application see this vibrant ecosystem of functionality is service discovery. Your application needs to listen to service broadcasts on the network to see what services are available, and filter out anything the application can't work with.

Service discovery, like service registration, has two steps: setting up a discovery listener with the relevant callbacks, and making a single asynchronous API call todiscoverServices().

First, instantiate an anonymous class that implements NsdManager.DiscoveryListener. The following snippet shows a simple example:

public void initializeDiscoveryListener() {    // Instantiate a new DiscoveryListener    mDiscoveryListener = new NsdManager.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());            } else if (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);            } else if (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);        }    };}

The NSD API uses the methods in this interface to inform your application when discovery is started, when it fails, and when services are found and lost (lost means "is no longer available"). Notice that this snippet does several checks when a service is found.

  1. The service name of the found service is compared to the service name of the local service to determine if the device just picked up its own broadcast (which is valid).
  2. The service type is checked, to verify it's a type of service your application can connect to.
  3. The service name is checked to verify connection to the correct application.

Checking the service name isn't always necessary, and is only relevant if you want to connect to a specific application. For instance, the application might only want to connect to instances of itself running on other devices. However, if the application wants to connect to a network printer, it's enough to see that the service type is "_ipp._tcp".

After setting up the listener, call discoverServices(), passing in the service type your application should look for, the discovery protocol to use, and the listener you just created.

    mNsdManager.discoverServices(        SERVICE_TYPE, NsdManager.PROTOCOL_DNS_SD, mDiscoveryListener);

Connect to Services on the Network

When your application finds a service on the network to connect to, it must first determine the connection information for that service, using theresolveService() method. Implement aNsdManager.ResolveListener to pass into this method, and use it to get aNsdServiceInfo containing the connection information.

public void initializeResolveListener() {    mResolveListener = new NsdManager.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();        }    };}

Once the service is resolved, your application receives detailed service information including an IP address and port number. This is everything you need to create your own network connection to the service.

Unregister Your Service on Application Close

It's important to enable and disable NSD functionality as appropriate during the application's lifecycle. Unregistering your application when it closes down helps prevent other applications from thinking it's still active and attempting to connect to it. Also, service discovery is an expensive operation, and should be stopped when the parent Activity is paused, and re-enabled when the Activity is resumed. Override the lifecycle methods of your main Activity and insert code to start and stop service broadcast and discovery as appropriate.

//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);    }
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 顺丰快递指定丰巢柜发现柜满怎么办 阿里购物申请退款过期末退怎么办 韵达签收了发现里面东西丢了怎么办 没有收到快递但是显示签收了怎么办 支付宝充话费显示商家未发货怎么办 快递被买家签收后调包了怎么办 快递买家签收了东西坏了怎么办 快递没签收到买家评价了怎么办 快递买家签收后现在要退货怎么办 支付宝充话费充错对方关机怎么办 闲鱼同意退款了买家不退东西怎么办 被骗了说给存q币怎么办 方正说我的淘宝字体侵权怎么办 买家说收到衣服没有吊牌该怎么办 淘宝下完订单店主不发货怎么办 工商局不给查被告企业的信息怎么办 被职业打假人起诉到法院怎么办 京东购物如果换货不给你发货怎么办 淘宝上发的快递没有了怎么办 天猫购物半个月不发货怎么办 京东网同一产品购买多规格的怎么办 天猫商城购买的家具要退换货怎么办 亚马逊美国站会员日前没销量怎么办 淘宝买的鞋子把脚磨坏了怎么办 拼多多下单 没货 没法发货怎么办 闲鱼退货物流弄坏了卖家拒收怎么办 客户说物流太慢了 要退货怎么办 京东退货物流系统不更新怎么办 把货交给物流但是物流丢货了怎么办 货还在物流就申请退款怎么办 荣耀4x返回键不管用怎么办 华为手机关不了机也开不了机怎么办 荣耀畅玩5x手机密码忘了怎么办 华为短信验证码失败其他错误怎么办 红米3x手机卡顿反应慢怎么办 华为手机不停的自动重启怎么办 华为荣耀4x卡在开机界面怎么办 华为荣耀8青春版密码忘了怎么办 华为手机内存满了开不起来怎么办 华为荣耀畅玩平板2比较卡怎么办 红米4x太卡了怎么办