Interview Questions

Example : A Time Server

Java Network Programming - Sockets for Servers


(Continued from previous question...)

Example : A Time Server

Sending binary, nontext data is not significantly harder. Example demonstrates with a time server. This follows the time protocol outlined in RFC 868. When a client connects, the server sends a 4-byte, big-endian, unsigned integer specifying the number of seconds that have passed since 12:00 A.M., January 1, 1900 GMT (the epoch). The current time can be retrieved simply by creating a new Date object. However, since the Date class counts milliseconds since 12:00 A.M., January 1, 1970 GMT rather than seconds since 12:00 A.M., January 1, 1900 GMT, some conversion is necessary.

    Example: A Time Server

    import java.net.*;
    import java.io.*;
    import java.util.Date;
      
    public class TimeServer {
      
 public final static int DEFAULT_PORT = 37;
     
 public static void main(String[] args) {
            
       int port = DEFAULT_PORT;     
       if (args.length > 0) {
         try {
       port = Integer.parseInt(args[0]);
     if (port < 0 || port >= 65536) {
 System.out.println
       ("Port must between 0 and 65535");
              return;      
            }
         }   
         catch (NumberFormatException e) {}  
       }     
     
// The time protocol sets the epoch at 1900,
 // the java Date class at 1970. This number 
// converts between them.
        
long differenceBetweenEpochs = 2208988800L;
        
 try {
 ServerSocket server = new ServerSocket(port);
           while (true) {
             Socket connection = null;
             try {
OutputStream out = connection.getOutputStream(  );
               Date now = new Date(  );
          long msSince1970 = now.getTime(  );
          long secondsSince1970 = msSince1970/1000;
          long secondsSince1900 = secondsSince1970 
                + differenceBetweenEpochs;
               byte[] time = new byte[4];
               time[0] 
= (byte) ((secondsSince1900 & 0x00000000FF000000L)
 >> 24); time[1] 
= (byte) ((secondsSince1900 & 0x0000000000FF0000L) 
 >> 16); time[2] 
 = (byte) ((secondsSince1900 & 0x000000000000FF00L)
  >> 8);  time[3] 
= (byte) (secondsSince1900 & 0x00000000000000FFL);
               out.write(time);
               out.flush(  );      
             } // end try
             catch (IOException e) {
             } // end catch
             finally {
    if (connection != null) connection.close(  ); 
             }
           }  // end while
       }  // end try
       catch (IOException e) {
         System.err.println(e);
       } // end catch
     
      } // end main
     
    } // end TimeServer

As with the TimeClient of the previous chapter, most of the effort here goes into working with a data format (32-bit unsigned integers) that Java doesn't natively support.
public void close( ) throws IOException

If you're finished with a server socket, you should close it, especially if your program is going to continue to run for some time. This frees up the port for other programs that may wish to use it. Closing a ServerSocket should not be confused with closing a Socket. Closing a ServerSocket frees a port on the local host, allowing another server to bind to the port; closing a Socket breaks the connection between the local and the remote hosts.

Server sockets are closed automatically when a program dies, so it's not absolutely necessary to close them in programs that terminate shortly after the ServerSocket is no longer needed. Nonetheless, it doesn't hurt. For example, the main loop of the LocalPortScanner program might be better written like this so that it doesn't temporarily occupy most of the ports on the system:


for (int port = 1; port <= 65535; port++)
{
     
      try {
// the next line will fail and drop into the 
//catch block if there is already a server
// running on the port
 ServerSocket server = new ServerSocket(port);
        server.close(  );
      }
      catch (IOException e) {
System.out.println("There is a server on port "
     + port + ".");
      } // end try
     
    } // end for

    The get Methods

The ServerSocket class provides two getter methods to tell you the local address and port occupied by the server socket. These are useful if you've opened a server socket on an anonymous port and/or an unspecified network interface. This would be the case, for one example, in the data connection of an FTP session.

public InetAddress getInetAddress( )

This method returns the address being used by the server (the local host). If the local host has a single IP address (as most do), then this is the address returned by InetAddress.getLocalHost( ). If the local host has more than one IP address, then the specific address returned is one of the host's IP addresses. You can't predict which address you will get. For example:

try {
  ServerSocket httpd = new ServerSocket(80);
  InetAddress ia = httpd.getInetAddress(  );
    }
    catch (IOException e) {
    }

    public int getLocalPort( )

The ServerSocket constructors allow you to listen on an unspecified port by passing 0 for the port number. This method lets you find out what port you're listening on. You might use this in a peer-to-peer multisocket program where you already have a means to inform other peers of your location. Or a server might spawn several smaller servers to perform particular operations. The well-known server could inform clients what ports they can find the smaller servers on. Of course, you can also use getLocalPort( ) to find a non-anonymous port.

(Continued on next question...)

Other Interview Questions