javaandroidclient-serverjmdnsdns-sd

communication between Java server and Android client using Network Service Discovery


I'm building a Java server application (running on a pc) that register itself to the local network using JmDNS, and an Android client App that should discover the java server using Network Service Discovery.
When I run the android app first, and then run the java server, the app succeed to discover the registerd java server.
But when I first run the server and then the android app, the onDiscoveryStarted method called but the onServiceFound method never triggered - the android app doesn't discover the server. This seems to me as an unexpected behavior.

Succeed case:
Android app log:
08-24 22:42:06.157 NSD_DISCOVER onCreate
08-24 22:42:06.373 NSD_DISCOVER﹕ onDiscoveryStarted Service discovery started
08-24 22:42:30.256 NSD_DISCOVER﹕ onServiceFound Known Service Type: _http._tcp.
08-24 22:42:30.293 NSD_DISCOVER﹕ onServiceResolved Resolve Succeeded. name: NsdApp, type: ._http._tcp, host: /10.0.0.2, port: 52288

Java server log:
START
REGISTERED
END
WAITING_FOR_MESSAGE
hello world
END_THREAD

Failure case:

Android app log:
08-24 22:05:21.690 NSD_DISCOVER﹕ onCreate
08-24 22:05:21.908 NSD_DISCOVER﹕ onDiscoveryStarted Service discovery started

Java server log:
START
REGISTERED
END
WAITING_FOR_MESSAGE

Server code

public class Server {

    public static String mServiceName = "NsdApp";
    public static final String SERVICE_TYPE = "_http._tcp.local";

    static ServerSocket mServerSocket;


    public static void main(String[] args) throws IOException {

        System.out.println("START");

    try {
        mServerSocket = new ServerSocket(0);
    } catch (IOException e) {
        System.out.println("ServerSocket(0) FAILED");
    }

    int mPort = mServerSocket.getLocalPort();

    JmDNS jmdns = JmDNS.create();
    ServiceInfo info = ServiceInfo.create(SERVICE_TYPE, mServiceName, mPort, "B");
    jmdns.registerService(info);

    System.out.println("REGISTERED");

    jmdns.close();

    Thread mReceiveMessage = new Thread(new ReceiveMessage());
    mReceiveMessage.start();

    System.out.println("END");
}

public static class ReceiveMessage implements Runnable {

    public void run() {
        System.out.println("WAITING_FOR_MESSAGE");
        try {

            Socket clientSocket = mServerSocket.accept(); 
            InputStreamReader inputStreamReader = new InputStreamReader(clientSocket.getInputStream());
            BufferedReader bufferedReader = new BufferedReader(inputStreamReader); 
            String message = bufferedReader.readLine();
            System.out.println(message);

            bufferedReader.close();
            inputStreamReader.close();
            clientSocket.close();
            System.out.println("END_THREAD");

        } catch (IOException ex) {
            System.out.println("Problem in message reading");
        }
    }
}
}

Client code

public class MainActivity extends Activity {

public static final String TAG = "NSD_DISCOVER";
public static final String SERVICE_TYPE = "_http._tcp.";
NsdManager.DiscoveryListener mDiscoveryListener;
NsdManager.ResolveListener mResolveListener;
NsdManager mNsdManager;
int port;
InetAddress host;


@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    Log.v(TAG, "onCreate");

    mNsdManager = (NsdManager) getSystemService(Context.NSD_SERVICE);
    initializeResolveListener();
    initializeDiscoveryListener();
    mNsdManager.discoverServices(SERVICE_TYPE, NsdManager.PROTOCOL_DNS_SD, mDiscoveryListener);
}


public void initializeDiscoveryListener() {
    mDiscoveryListener = new NsdManager.DiscoveryListener() {

        @Override
        public void onDiscoveryStarted(String regType) {
            Log.v(TAG, "onDiscoveryStarted Service discovery started");
        }

        @Override
        public void onServiceFound(NsdServiceInfo service) {
            if (!service.getServiceType().equals(SERVICE_TYPE)) {
                Log.v(TAG, "onServiceFound Unknown Service Type: " + service.getServiceType());
            } else {
                Log.v(TAG, "onServiceFound Known Service Type: " + service.getServiceType());
                mNsdManager.resolveService(service, mResolveListener);
            }
        }

        @Override
        public void onServiceLost(NsdServiceInfo service) {
            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);
        }
    };
}


public void initializeResolveListener() {
    mResolveListener = new NsdManager.ResolveListener() {

        @Override
        public void onResolveFailed(NsdServiceInfo serviceInfo, int errorCode) {
            Log.e(TAG, "onResolveFailed Resolve failed" + errorCode);
        }

        @Override
        public void onServiceResolved(NsdServiceInfo serviceInfo) {
            Log.v(TAG, "onServiceResolved Resolve Succeeded. " + serviceInfo);
            port = serviceInfo.getPort();
            host = serviceInfo.getHost();

            SendMessage sendMessageTask = new SendMessage();
            sendMessageTask.execute();
        }
    };
}


private class SendMessage extends AsyncTask<Void, Void, Void> {

    @Override
    protected Void doInBackground(Void... params) {
        try {

            Socket client;
            PrintWriter printwriter;

            client = new Socket(host, port); 
            printwriter = new PrintWriter(client.getOutputStream(), true);
            printwriter.write("hello world"); 

            printwriter.flush();
            printwriter.close();
            client.close(); 

        } catch (UnknownHostException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }
}

}


Solution

  • You are calling jmdns.close() right after registering. Your service is only discoverable as long as you have jmdns open. You should remove that call to close, make your jmdns variable a member of your class, and then only call close on it when you don't want your services to be discoverable anymore. Also, it is good form to call unregisterAllServices() before closing jmdns.