title: issue with reliable service discovery
body: <p>I am banging my head on the wall. It works, but it doesn't work.</p>
  
  <p>Let me clarify, testing is on a LG Optimus G, A Galaxy S4, and a Lenovo Tablet all running 4.1+</p>
  
  <p>I am launching a server on each device, each device is broadcasting itself on a port, and when the user hits send, all devices that have had their service resolved, and their service has not been lost, a thread will loop launching other threads to connect to the servers broadcasting themselves, and send the data. The servers accept the incoming connection, hand it off to a thread, and then re-open themselves.</p>
  
  <p>So recap, every device has is broadcasting a server, every device is supposed to know and keep track of other servers, when data is sent all known servers get hit.</p>
  
  <p>My issue is that in 2/3 devices connections can consistently be established with the device's self.</p>
  
  <p>Either phone, but only 1 of them at a time, seems to know about the other phone and is able to connect to the other phone. i.e. Galaxy S4 can say hi to Optimus G, but Optimus G cannot say hi except only to itself, or vice-verse.</p>
  
  <p>So the discovering portion seems unreliable, and I do not know if it is me, Android, or the devices. I need outside eyes. I have tried to lay this out in a understandable and thought out manner, and I appreciate any help from any one who has knowledge on this issue as I am just making humble beginnings into the world of networks, and am more then willing to learn from someone.</p>
  
  <p>I need a more reliable way of keeping track of services, or discovering them, as my implementation at least seems flawed.</p>
  
  <p>I thank any help in advanced. (I do not believe this is a area that is trodden as heavily as most other android areas.)</p>
  
  <p>Here is where the initialization is done.</p>
  
  <pre><code>/**initilize everything*/
  private void buildNetwork()
  {
      Log.d(TAG, "buildNetwork");
      networkHelper = new NetworkServiceDiscoveryHelper(this);
      networkHelper.initializeNsd(this);
      networkHelper.discoverServices();
      connectionReceiver = new ConnectionReceiver(this, this);
      // this next line launches the server thread which will obtain a socket
      // to be used in the finishBuildingNetwork()
      new Thread(connectionReceiver).start();
  
  }
  
  /** after the serversocket has been given a port we need to broadcast it*/
  private void finishBuildingNetwork(int port)
  {
      Log.d(TAG, "finishBuildingNetwork");
      networkHelper.registerService(port);
  }
  </code></pre>
  
  <p>This is my somewhat changed implementation of a common <code>NSDManager</code> helper class.</p>
  
  <pre><code>public class NetworkServiceDiscoveryHelper
  {
  
      public static final String TAG = "NetworkServiceDiscoveryHelper";
      public static final String KEY_DEVICE = "device";
  
      Context mContext;
  
      NsdManager mNsdManager;
      NsdManager.ResolveListener mResolveListener;
      NsdManager.DiscoveryListener mDiscoveryListener;
      NsdManager.RegistrationListener mRegistrationListener;
  
      public static final String SERVICE_TYPE = "_http._tcp.";
  
      public String mServiceName = "BlurbChat";
  
      NsdServiceInfo mService;
  
      private DiscoveredDevicesManager deviceManager;
      private NetworkDiscoveryHelperListener helperListener;
  
      /**
       * 
       * @param context
       *            - the activity context the service is to be attached to
       */
      public NetworkServiceDiscoveryHelper(Context context)
      {
          mContext = context;
          mNsdManager = (NsdManager) context.getSystemService(Context.NSD_SERVICE);
          deviceManager = new DiscoveredDevicesManager();
      }
  
      /**
       * initialize the NetworkServiceDiscovery
       */
      public void initializeNsd(NetworkDiscoveryHelperListener helperListener)
      {
          this.helperListener = helperListener;
  
          initializeResolveListener();
          initializeDiscoveryListener();
          initializeRegistrationListener();
  
          // mNsdManager.init(mContext.getMainLooper(), this);
  
      }
  
      private void initializeDiscoveryListener()
      {
          mDiscoveryListener = new NsdManager.DiscoveryListener()
          {
  
              @Override
              public void onDiscoveryStarted(String regType)
              {
                  Log.d(TAG, "Service discovery started");
                  helperListener.SERVICE_STARTED(regType);
              }
  
              @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().contains(mServiceName))
                  {
                      // we have found our service! we use .contains because if
                      // there are multiple device with the same service being
                      // broadcast they will appear with name + (index)
                      // Resolve a discovered service. An application can resolve
                      // a service right before establishing a connection to fetch
                      // the IP and port details on which to setup the connection.
                      Log.d(TAG, "Found My Service Type: " + service.getServiceType() + service.getServiceName());
                      helperListener.SERVICE_FOUND(service);
                      mNsdManager.resolveService(service, mResolveListener);
                  }
  
                  /***************************************************************
                   * 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".
                   ******************************************************/
              }
  
              /**
               * when we lose our service
               */
              @Override
              public void onServiceLost(NsdServiceInfo service)
              {
                  // When the network service is no longer available.
                  Log.e(TAG, "service lost" + service);
  
                  // remove the service
                  if (deviceManager.removeDevice(service) != null)
                  {
                      helperListener.SERVIVCE_LOST(service);
                  }
              }
  
              /**
               * when our service is stopped
               */
              @Override
              public void onDiscoveryStopped(String serviceType)
              {
                  Log.i(TAG, "Discovery stopped: " + serviceType);
                  helperListener.DISCOVERY_STOPPED(serviceType);
              }
  
              @Override
              public void onStartDiscoveryFailed(String serviceType, int errorCode)
              {
                  Log.e(TAG, "Discovery failed: Error code:" + errorCode);
                  helperListener.DISCOVERY_START_FAILED(serviceType, errorCode);
                  mNsdManager.stopServiceDiscovery(this);
              }
  
              @Override
              public void onStopDiscoveryFailed(String serviceType, int errorCode)
              {
                  helperListener.DISCOVERY_STOP_FAILED(serviceType, errorCode);
                  Log.e(TAG, "Discovery failed: Error code:" + errorCode);
                  mNsdManager.stopServiceDiscovery(this);
              }
          };
      }
  
      private 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);
                  helperListener.RESOLVE_FAILED(serviceInfo, 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;
                  DiscoveredDevice device = new DiscoveredDevice(mService.getPort(), mService.getHost(), mService.getServiceName(), mService.getServiceType());
                  deviceManager.addDevice(device);
                  helperListener.RESOLVE_SUCCESS(serviceInfo);
              }
          };
      }
  
      private void initializeRegistrationListener()
      {
          mRegistrationListener = new NsdManager.RegistrationListener()
          {
  
              @Override
              public void onServiceRegistered(NsdServiceInfo serviceInfo)
              {
                  mServiceName = serviceInfo.getServiceName();
                  helperListener.SERVICE_REGISTERED(serviceInfo);
              }
  
              @Override
              public void onRegistrationFailed(NsdServiceInfo serviceInfo, int errorCode)
              {
                  helperListener.SERVICE_REGISTRATION_FAILED(serviceInfo, errorCode);
              }
  
              @Override
              public void onServiceUnregistered(NsdServiceInfo serviceInfo)
              {
                  helperListener.SERVICE_UNREGISTERED(serviceInfo);
              }
  
              @Override
              public void onUnregistrationFailed(NsdServiceInfo serviceInfo, int errorCode)
              {
                  helperListener.SERVICE_UNREGISTRATION_FAILED(serviceInfo, errorCode);
              }
  
          };
      }
  
      /**
       * To be called after initialize()
       * 
       * @param port
       *            - the port you would like to register/broadcast the service through.
       */
      public void registerService(int port)
      {
          NsdServiceInfo serviceInfo = new NsdServiceInfo();
          serviceInfo.setPort(port);
          serviceInfo.setServiceName(mServiceName);
          serviceInfo.setServiceType(SERVICE_TYPE);
  
          mNsdManager.registerService(serviceInfo, NsdManager.PROTOCOL_DNS_SD, mRegistrationListener);
  
      }
  
      /**
       * Initiate service discovery to browse for instances of a service type. Service discovery consumes network bandwidth and will continue
       * until the application calls stopServiceDiscovery(NsdManager.DiscoveryListener).
       */
      public void discoverServices()
      {
          mNsdManager.discoverServices(SERVICE_TYPE, NsdManager.PROTOCOL_DNS_SD, mDiscoveryListener);
      }
  
      /**
       * Stop service discovery initiated with discoverServices(String, int, NsdManager.DiscoveryListener). An active service discovery is
       * notified to the application with onDiscoveryStarted(String) and it stays active until the application invokes a stop service
       * discovery. A successful stop is notified to with a call to onDiscoveryStopped(String).
       */
      public void stopDiscovery()
      {
          mNsdManager.stopServiceDiscovery(mDiscoveryListener);
      }
  
      /**
       * 
       * @return - A class representing service information for network service discovery
       */
      public NsdServiceInfo getChosenServiceInfo()
      {
          return mService;
      }
  
      /**
       * Unregister a service registered through registerService(NsdServiceInfo, int, NsdManager.RegistrationListener). A successful
       * unregister is notified to the application with a call to onServiceUnregistered(NsdServiceInfo).
       */
      public void tearDown()
      {
          if (mNsdManager != null)
          {
              try
              {
                  mNsdManager.unregisterService(mRegistrationListener);
                  mNsdManager.stopServiceDiscovery(mDiscoveryListener);
              }
              catch (Exception e)
              {
                  e.printStackTrace();
              }
          }
      }
  
      /**
       * 
       * @return - the DiscoveredDevicesManager that contains all valid devices which have the appropriate service susally will call this
       *         after a msg of RESOLVE_SUCCESS
       */
      public DiscoveredDevicesManager getDeviceManager()
      {
          return deviceManager;
      }
  
  }
  </code></pre>
  
  <p>and finally this is the basis of the server</p>
  
  <pre><code>    @Override
      public void run()
      {
          try
          {
              receiverSocket = new ServerSocket(0);
  
              onPortObtained(receiverSocket.getLocalPort());
  
              Log.d(TAG, "run");
              while (broadcastConnection)
              {
                  try
                  {
                      Socket newConnectionSocket = receiverSocket.accept();
                      onNewConnection(newConnectionSocket.getRemoteSocketAddress(), newConnectionSocket.getLocalSocketAddress());
                                      // to clarify this line launches a function that starts threads to handle the socket.
                      recieveConnection(newConnectionSocket);
  
                  }
                  catch (IOException e)
                  {
                      e.printStackTrace();
                  }
              }
          }
          catch (IOException e1)
          {
              e1.printStackTrace();
          }
      }
  </code></pre>
  
  <p>Edit: one more thing, sometimes while running the devices will randomly restart. No common thing causing, other then they are running the app.</p>