July 26, 2014
Hot Topics:
RSS RSS feed Download our iPhone app

Dynamic Service Discovery with Java

  • February 19, 2008
  • By Rob Lybarger
  • Send Email »
  • More Articles »

And now the client:

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.InetAddress;
import java.net.Socket;

public class TimeClient {
  public static void main(String[] args) {
    try {
      Socket socket = new Socket(InetAddress.getLocalHost(), 9999);
      InputStreamReader reader =
          new InputStreamReader(socket.getInputStream());
      BufferedReader bufferedReader = new BufferedReader(reader);
      String line = bufferedReader.readLine();
      System.out.println(line);
      socket.close();
    }
    catch (IOException ie) {
      System.err.println("Exception: "+ie);
      System.exit(1);
    }

    System.out.println("\nThat's all, folks.");
    System.exit(0);
  }
}

This is a completely straightforward, no-frills TCP network server and client application. The important point to note is the hard-coded port, 9999, in both the server and the client, and the hard-coded server address (that for the localhost, in this case) in the client. Although these values can be put into property or configuration files, they are still effectively static, fixed values. If the server, running on one machine, changes port numbers, but the client isn't aware of this, it will just look like the server is unavailable.

But, with just a little addition using a few classes (that you can download and experiment with on your own), making things be completely dynamic is fairly simple. First is the new server code:

  public static void main(String[] args) {

    ServerSocket serverSocket = null;
    String SERVICE_NAME  = "timeDemo";
    String INSTANCE_NAME = "Time_Server_1";
    
    try {
      serverSocket = new ServerSocket();
      serverSocket.bind(
          new InetSocketAddress(InetAddress.getLocalHost(),
          0));    /*bind to any available port number*/
    }
    catch (IOException ioe) {
      System.err.println(
          "Could not bind a server socket to a free port: "+ioe);
      System.exit(1);
    }
    
    /* Create a descriptor for the service you are providing. */
    ServiceDescription descriptor = new ServiceDescription();
    descriptor.setAddress(serverSocket.getInetAddress());
    descriptor.setPort(serverSocket.getLocalPort());
    descriptor.setInstanceName(INSTANCE_NAME);
    System.out.println("Service details: "+descriptor);

    /* Read special note for code you should add here */

    /*
     * Set up a responder and give it the descriptor (above)
     * we want to publish. Start the responder, which
     * works in its own thread.
     */
    ServiceResponder responder =
        new ServiceResponder(SERVICE_NAME);
    responder.setDescriptor(descriptor);
    responder.startResponder();

    /* Back to the usual routine of servicing requests */
    System.out.println(
        "Responder listening. Now taking connections...");
    while (true) {
      try {
        Socket socket = serverSocket.accept();
        System.out.println(
            "Connection from: "+socket.getInetAddress());
        OutputStreamWriter writer =
            new OutputStreamWriter(socket.getOutputStream());
        writer.write(new Date().toString()+"\r\n");
        writer.flush();
        socket.close();
      }
      catch (IOException ie) {
        System.err.println("Exception: "+ie);
      }
    }

The important aspects of this change are that, once the service knows the address and port it is running on, a "descriptor" object is created. (This object is just a plain data container.) Then, a "responder" is created and passed the descriptor object for the service. This responder forms the server-side half of the service discovery code. Running in its own thread, it binds to an internally configured multicast channel, listens for lookup queries, and sends back a reply containing the information in this descriptor. That's about it. The rest of the Time Server runs exactly as it did before: listening for connections on the port it is running on, and pushing across the current time.

The comment in the modified server code mentions a special note. At this location, you should really arrange for the server to make its own lookup query (you'll see how in a moment) to check that the instance name it wants to use has not yet been claimed. (If it has, the instance name should be modified, and the check repeated as needed.) I've omitted this partly for clarity, and partly to not duplicate what you will see in the client code.





Page 3 of 4



Comment and Contribute

 


(Maximum characters: 1200). You have characters left.

 

 


Sitemap | Contact Us

Rocket Fuel