Home | History | Annotate | Download | only in connect-devices-wirelessly
      1 page.title=Using Network Service Discovery
      2 
      3 trainingnavtop=true
      4 
      5 @jd:body
      6 
      7 <div id="tb-wrapper">
      8 <div id="tb">
      9 
     10 <!-- table of contents -->
     11 <h2>This lesson teaches you how to</h2>
     12 <ol>
     13   <li><a href="#register">Register Your Service on the Network</a></li>
     14   <li><a href="#discover">Discover Services on the Network</a></li>
     15   <li><a href="#connect">Connect to Services on the Network</a></li>
     16   <li><a href="#teardown">Unregister Your Service on Application Close</a></li>
     17 </ol>
     18 
     19 <!--
     20 <h2>You should also read</h2>
     21     <ul>
     22     </ul>
     23 -->
     24 <h2>Try it out</h2>
     25 
     26 <div class="download-box">
     27   <a href="{@docRoot}shareables/training/NsdChat.zip" class="button">Download
     28     the sample app</a>
     29   <p class="filename">NsdChat.zip</p>
     30 </div>
     31 </p>
     32 
     33 </div>
     34 </div>
     35 
     36 <p>Adding Network Service Discovery (NSD) to your app allows your users to
     37 identify other devices on the local network that support the services your app
     38 requests. This is useful for a variety of peer-to-peer applications such as file
     39 sharing or multi-player gaming. Android's NSD APIs simplify the effort required
     40 for you to implement such features.</p>
     41 
     42 <p>This lesson shows you how to build an application that can broadcast its
     43 name and connection information to the local network and scan for information
     44 from other applications doing the same.  Finally, this lesson shows you how
     45 to connect to the same application running on another device.</p>
     46 
     47 <h2 id="register">Register Your Service on the Network</h2>
     48 
     49 <p class="note"><strong>Note: </strong>This step is optional.  If
     50 you don't care about broadcasting your app's services over the local network,
     51 you can skip forward to the
     52 next section, <a href="#discover">Discover Services on the Network</a>.</p>
     53 
     54 <p>To register your service on the local network, first create a {@link
     55 android.net.nsd.NsdServiceInfo} object.  This object provides the information
     56 that other devices on the network use when they're deciding whether to connect to your
     57 service. </p>
     58 
     59 <pre>
     60 public void registerService(int port) {
     61     // Create the NsdServiceInfo object, and populate it.
     62     NsdServiceInfo serviceInfo  = new NsdServiceInfo();
     63 
     64     // The name is subject to change based on conflicts
     65     // with other services advertised on the same network.
     66     serviceInfo.setServiceName("NsdChat");
     67     serviceInfo.setServiceType("_http._tcp.");
     68     serviceInfo.setPort(port);
     69     ....
     70 }
     71 </pre>
     72 
     73 <p>This code snippet sets the service name to "NsdChat".
     74 The name is visible to any device on the network that is using NSD to look for
     75 local services.  Keep in mind that the name must be unique for any service on the
     76 network, and Android automatically handles conflict resolution.  If
     77 two devices on the network both have the NsdChat application installed, one of
     78 them changes the service name automatically, to something like "NsdChat
     79 (1)".</p>
     80 
     81 <p>The second parameter sets the service type, specifies which protocol and transport
     82 layer the application uses.  The syntax is
     83 "_&lt;protocol&gt;._&lt;transportlayer&gt;".  In the
     84 code snippet, the service uses HTTP protocol running over TCP.  An application
     85 offering a printer service (for instance, a network printer) would set the
     86 service type to "_ipp._tcp".</p>
     87 
     88 <p class="note"><strong>Note: </strong> The International Assigned Numbers
     89 Authority (IANA) manages a centralized,
     90 authoritative list of service types used by service discovery protocols such as NSD and Bonjour.
     91 You can download the list from <a
     92   href="http://www.iana.org/assignments/service-names-port-numbers/service-names-port-numbers.xml">the
     93 IANA list of service names and port numbers</a>.
     94 If you intend to use a new service type, you should reserve it by filling out
     95 the  <a
     96   href="http://www.iana.org/form/ports-services">IANA Ports and Service
     97   registration form</a>.</p>
     98 
     99 <p>When setting the port for your service, avoid hardcoding it as this
    100 conflicts with other applications.  For instance, assuming
    101 that your application always uses port 1337 puts it in potential conflict with
    102 other installed applications that use the same port.  Instead, use the device's
    103 next available port.  Because this information is provided to other apps by a
    104 service broadcast, there's no need for the port your application uses to be
    105 known by other applications at compile-time.  Instead, the applications can get
    106 this information from your service broadcast, right before connecting to your
    107 service.</p>
    108 
    109 <p>If you're working with sockets, here's how you can initialize a socket to any
    110 available port simply by setting it to 0.</p>
    111 
    112 <pre>
    113 public void initializeServerSocket() {
    114     // Initialize a server socket on the next available port.
    115     mServerSocket = new ServerSocket(0);
    116 
    117     // Store the chosen port.
    118     mLocalPort =  mServerSocket.getLocalPort();
    119     ...
    120 }
    121 </pre>
    122 
    123 <p>Now that you've defined the {@link android.net.nsd.NsdServiceInfo
    124 NsdServiceInfo} object, you need to implement the {@link
    125 android.net.nsd.NsdManager.RegistrationListener RegistrationListener} interface.  This
    126 interface contains callbacks used by Android to alert your application of the
    127 success or failure of service registration and unregistration.
    128 </p>
    129 <pre>
    130 public void initializeRegistrationListener() {
    131     mRegistrationListener = new NsdManager.RegistrationListener() {
    132 
    133         &#64;Override
    134         public void onServiceRegistered(NsdServiceInfo NsdServiceInfo) {
    135             // Save the service name.  Android may have changed it in order to
    136             // resolve a conflict, so update the name you initially requested
    137             // with the name Android actually used.
    138             mServiceName = NsdServiceInfo.getServiceName();
    139         }
    140 
    141         &#64;Override
    142         public void onRegistrationFailed(NsdServiceInfo serviceInfo, int errorCode) {
    143             // Registration failed!  Put debugging code here to determine why.
    144         }
    145 
    146         &#64;Override
    147         public void onServiceUnregistered(NsdServiceInfo arg0) {
    148             // Service has been unregistered.  This only happens when you call
    149             // NsdManager.unregisterService() and pass in this listener.
    150         }
    151 
    152         &#64;Override
    153         public void onUnregistrationFailed(NsdServiceInfo serviceInfo, int errorCode) {
    154             // Unregistration failed.  Put debugging code here to determine why.
    155         }
    156     };
    157 }
    158 </pre>
    159 
    160 <p>Now you have all the pieces to register your service.  Call the method
    161 {@link android.net.nsd.NsdManager#registerService registerService()}.
    162 </p>
    163 
    164 <p>Note that this method is asynchronous, so any code that needs to run
    165 after the service has been registered must go in the {@link
    166 android.net.nsd.NsdManager.RegistrationListener#onServiceRegistered(NsdServiceInfo)
    167 onServiceRegistered()} method.</p>
    168 
    169 <pre>
    170 public void registerService(int port) {
    171     NsdServiceInfo serviceInfo  = new NsdServiceInfo();
    172     serviceInfo.setServiceName("NsdChat");
    173     serviceInfo.setServiceType("_http._tcp.");
    174     serviceInfo.setPort(port);
    175 
    176     mNsdManager = Context.getSystemService(Context.NSD_SERVICE);
    177 
    178     mNsdManager.registerService(
    179             serviceInfo, NsdManager.PROTOCOL_DNS_SD, mRegistrationListener);
    180 }
    181 </pre>
    182 
    183 <h2 id="discover">Discover Services on the Network</h2>
    184 <p>The network is teeming with life, from the beastly network printers to the
    185 docile network webcams, to the brutal, fiery battles of nearby tic-tac-toe
    186 players.  The key to letting your application see this vibrant ecosystem of
    187 functionality is service discovery.  Your application needs to listen to service
    188 broadcasts on the network to see what services are available, and filter out
    189 anything the application can't work with.</p>
    190 
    191 <p>Service discovery, like service registration, has two steps:
    192  setting up a discovery listener with the relevant callbacks, and making a single asynchronous
    193 API call to {@link android.net.nsd.NsdManager#discoverServices(String
    194 , int , NsdManager.DiscoveryListener) discoverServices()}.</p>
    195 
    196 <p>First, instantiate an anonymous class that implements {@link
    197 android.net.nsd.NsdManager.DiscoveryListener}.  The following snippet shows a
    198 simple example:</p>
    199 
    200 <pre>
    201 public void initializeDiscoveryListener() {
    202 
    203     // Instantiate a new DiscoveryListener
    204     mDiscoveryListener = new NsdManager.DiscoveryListener() {
    205 
    206         //  Called as soon as service discovery begins.
    207         &#64;Override
    208         public void onDiscoveryStarted(String regType) {
    209             Log.d(TAG, "Service discovery started");
    210         }
    211 
    212         &#64;Override
    213         public void onServiceFound(NsdServiceInfo service) {
    214             // A service was found!  Do something with it.
    215             Log.d(TAG, "Service discovery success" + service);
    216             if (!service.getServiceType().equals(SERVICE_TYPE)) {
    217                 // Service type is the string containing the protocol and
    218                 // transport layer for this service.
    219                 Log.d(TAG, "Unknown Service Type: " + service.getServiceType());
    220             } else if (service.getServiceName().equals(mServiceName)) {
    221                 // The name of the service tells the user what they'd be
    222                 // connecting to. It could be "Bob's Chat App".
    223                 Log.d(TAG, "Same machine: " + mServiceName);
    224             } else if (service.getServiceName().contains("NsdChat")){
    225                 mNsdManager.resolveService(service, mResolveListener);
    226             }
    227         }
    228 
    229         &#64;Override
    230         public void onServiceLost(NsdServiceInfo service) {
    231             // When the network service is no longer available.
    232             // Internal bookkeeping code goes here.
    233             Log.e(TAG, "service lost" + service);
    234         }
    235 
    236         &#64;Override
    237         public void onDiscoveryStopped(String serviceType) {
    238             Log.i(TAG, "Discovery stopped: " + serviceType);
    239         }
    240 
    241         &#64;Override
    242         public void onStartDiscoveryFailed(String serviceType, int errorCode) {
    243             Log.e(TAG, "Discovery failed: Error code:" + errorCode);
    244             mNsdManager.stopServiceDiscovery(this);
    245         }
    246 
    247         &#64;Override
    248         public void onStopDiscoveryFailed(String serviceType, int errorCode) {
    249             Log.e(TAG, "Discovery failed: Error code:" + errorCode);
    250             mNsdManager.stopServiceDiscovery(this);
    251         }
    252     };
    253 }
    254 </pre>
    255 
    256 <p>The NSD API uses the methods in this interface to inform your application when discovery
    257 is started, when it fails, and when services are found and lost (lost means "is
    258 no longer available").  Notice that this snippet does several checks
    259 when a service is found.</p>
    260 <ol>
    261   <li>The service name of the found service is compared to the service
    262 name of the local service to determine if the device just picked up its own
    263 broadcast (which is valid).</li>
    264 <li>The service type is checked, to verify it's a type of service your
    265 application can connect to.</li>
    266 <li>The service name is checked to verify connection to the correct
    267 application.</li>
    268 </ol>
    269 
    270 <p>Checking the service name isn't always necessary, and is only relevant if you
    271 want to connect to a specific application.  For instance, the application might
    272 only want to connect to instances of itself running on other devices.  However, if the
    273 application wants to connect to a network printer, it's enough to see that the service type
    274 is "_ipp._tcp".</p>
    275 
    276 <p>After setting up the listener, call {@link android.net.nsd.NsdManager#discoverServices(String, int,
    277 NsdManager.DiscoveryListener) discoverServices()}, passing in the service type
    278 your application should look for, the discovery protocol to use, and the
    279 listener you just created.</p>
    280 
    281 <pre>
    282     mNsdManager.discoverServices(
    283         SERVICE_TYPE, NsdManager.PROTOCOL_DNS_SD, mDiscoveryListener);
    284 </pre>
    285 
    286 
    287 <h2 id="connect">Connect to Services on the Network</h2>
    288 <p>When your application finds a service on the network to connect to, it
    289 must first determine the connection information for that service, using the
    290 {@link android.net.nsd.NsdManager#resolveService resolveService()} method.
    291 Implement a {@link android.net.nsd.NsdManager.ResolveListener} to pass into this
    292 method, and use it to get a {@link android.net.nsd.NsdServiceInfo} containing
    293 the connection information.</p>
    294 
    295 <pre>
    296 public void initializeResolveListener() {
    297     mResolveListener = new NsdManager.ResolveListener() {
    298 
    299         &#64;Override
    300         public void onResolveFailed(NsdServiceInfo serviceInfo, int errorCode) {
    301             // Called when the resolve fails.  Use the error code to debug.
    302             Log.e(TAG, "Resolve failed" + errorCode);
    303         }
    304 
    305         &#64;Override
    306         public void onServiceResolved(NsdServiceInfo serviceInfo) {
    307             Log.e(TAG, "Resolve Succeeded. " + serviceInfo);
    308 
    309             if (serviceInfo.getServiceName().equals(mServiceName)) {
    310                 Log.d(TAG, "Same IP.");
    311                 return;
    312             }
    313             mService = serviceInfo;
    314             int port = mService.getPort();
    315             InetAddress host = mService.getHost();
    316         }
    317     };
    318 }
    319 </pre>
    320 
    321 <p>Once the service is resolved, your application receives detailed
    322 service information including an IP address and port number.  This is  everything
    323 you need to create your own network connection to the service.</p>
    324 
    325 
    326 <h2 id="teardown">Unregister Your Service on Application Close</h2>
    327 <p>It's important to enable and disable NSD
    328 functionality as appropriate during the application's
    329 lifecycle.  Unregistering your application when it closes down helps prevent
    330 other applications from thinking it's still active and attempting to connect to
    331 it.  Also, service discovery is an expensive operation, and should be stopped
    332 when the parent Activity is paused, and re-enabled when the Activity is
    333 resumed.  Override the lifecycle methods of your main Activity and insert code
    334 to start and stop service broadcast and discovery as appropriate.</p>
    335 
    336 <pre>
    337 //In your application's Activity
    338 
    339     &#64;Override
    340     protected void onPause() {
    341         if (mNsdHelper != null) {
    342             mNsdHelper.tearDown();
    343         }
    344         super.onPause();
    345     }
    346 
    347     &#64;Override
    348     protected void onResume() {
    349         super.onResume();
    350         if (mNsdHelper != null) {
    351             mNsdHelper.registerService(mConnection.getLocalPort());
    352             mNsdHelper.discoverServices();
    353         }
    354     }
    355 
    356     &#64;Override
    357     protected void onDestroy() {
    358         mNsdHelper.tearDown();
    359         mConnection.tearDown();
    360         super.onDestroy();
    361     }
    362 
    363     // NsdHelper's tearDown method
    364         public void tearDown() {
    365         mNsdManager.unregisterService(mRegistrationListener);
    366         mNsdManager.stopServiceDiscovery(mDiscoveryListener);
    367     }
    368 </pre>
    369 
    370