Programming Servers Using Sockets

So far we have only looked at clients in Java, assuming that servers were ready and available. It is just as easy to write a server in Java. The new library class involved is the ServerSocket class. Servers often use multi-threading.

A Socket object is a connection to a particular host on a particular port. But a SocketServer object just waits on a particular port for incoming connections from anywhere. When a client attempts to connect, the server wakes up and a Socket object is created. Thereafter the server uses the socket to send and receive data to and from that client. So:


The ServerSocket class

This class, together with the Socket class, provides all the facilities necessary to write servers in Java. It provides methods to:

In general the server works like this:

  1. A ServerSocket object is created on a particular port.
  2. The ServerSocket object listens for any connection attempts using the method accept(). The server is blocked (waits) until a client attempts to connect. When a client connects, method accept() returns a Socket object representing the connection between the server and the client.
  3. The Socket object's getInputStream() and/or getOutputStream() methods are called to obtain streams which can be used to send and receive data. (This is the same mechanism we saw with a client.)
  4. The server and the client interact using streams according to an agreed protocol.
  5. The server, the client, or both close the connection.
  6. The server returns to step 2, to wait for the next connection.

Although this is a general pattern, things are not always so simple, and a different approach is needed if the communication between client and server (step 4) is time-consuming.


Example - A Daytime Server

This is one of the simplest servers, implementing the daytime protocol. The client connects, but sends no data. The server simply sends the time and date as a text string and then closes the connection.

The server waits for connections by calling accept(), within in an infinite loop. When a client connects, a new Socket object is created. The date is obtained by calling the library class Date. After dispatch of the information, the socket (but not the ServerSocket) is closed. Here is the relevant

Program Pseudocode

Create a server socket on port 13
while true do
    Wait for a connection from a client
    Look up the date and time
    Send the date and time to the client
    Close the socket
endWhile
// DaytimeServer.java
// Provides the date and time on the current server
// at port number 7013.

import java.net.*;
import java.io.*;
import java.util.Date;

public class DaytimeServer
{
    public final static int DAYTIME_PORT = 7013;

    public static void main(String[] args)
    {
        ServerSocket server;
        Socket socket;

        try
        {
            server = new ServerSocket(DAYTIME_PORT);
            try
            {
                while (true)
                {
                    socket = server.accept();
                    PrintWriter out = new
                         PrintWriter(socket.getOutputStream(), true);
                    Date date = new Date();
                    out.println(date.toString());
                    socket.close();
                }
            }
            catch (IOException e)
            {
                server.close();
                System.err.println(e);
            }
        }
        catch (IOException e)
        {
            System.err.println(e);
        }
    }
}

A Simple Web Server

Finally we look at the design and code of a web server - a server that implements HTTP. This is a large protocol and a full-blown server would need to:

// WebServer.java
// Serves up static HTML web pages from a
// local subdirectory called "webpages".

import java.net.*;
import java.io.*;
import java.util.*;

public class WebServer
{
    public final static int WEB_PORT = 7080;
    public final String docRoot = "webpages";
    BufferedReader in;
    PrintWriter out;

    public static void main(String[] args)
    {
        WebServer ws = new WebServer();
        ws.waitForRequest();
    }

    public void waitForRequest()
    {
        ServerSocket server;
        Socket socket;

        try
        {
            server = new ServerSocket(WEB_PORT);
            try
            {
                while (true)
                {
                    socket = server.accept();
                    serviceRequest(socket);
                    socket.close();
                 }
            }
            catch (IOException e)
            {
                server.close();
                System.err.println(e);
            }
        }
        catch (IOException e)
        {
            System.err.println(e);
        }
    }

    public void serviceRequest(Socket socket)
    {
        try
        {
            in = new BufferedReader(new
                InputStreamReader(socket.getInputStream()));

            out = new PrintWriter(socket.getOutputStream(), true);
            String line = in.readLine();
            StringTokenizer st = new StringTokenizer(line);
            String command = st.nextToken();
            if (command.equals("GET"))
            {
                sendFile(st.nextToken());
                skipRemainder();
            }
            else
                notImplemented();
            socket.close();
        }
        catch (IOException e) {}
    }

    public void sendFile(String fileName)
    {
        try
        {
            String completeName = docRoot + fileName;
            BufferedReader file = new BufferedReader(new
                FileReader(completeName));
            sendHeader((new File(completeName)).length());
            String line;
            while ((line = file.readLine()) != null)
                out.println(line);
        }
        catch (IOException e)
        {
            fileNotFound();
        }
    }

    public void skipRemainder()        {}
    public void sendHeader(long length){}
    public void fileNotFound()         {}
    public void notImplemented()
    {
        out.println("<HTML><HEAD><TITLE>Not Implemented</TITLE></HEAD>");
        out.println("<BODY><H1>HTTP Error 501:" +
                    "Not Implemented</H1></BODY></HTML>");
    }
}


Multi-Threading

A server may be bombarded with requests from a number of different clients within a short time. If the server program accepts the first request but then dedicates itself exclusively to servicing it, all other requests will be locked out. The above server program blocks (waits) on the readLine statement while a line is transferred from slow disk storage. While it is waiting, nothing else can be done. This is a common practice, to create a new thread to handle each client. These run concurrently and any one can be blocked while others continue. Java provides facilities for this multi-threading.


So, the Java library class ServerSocket allows a server program to wait for a connection from a client, and then deal with that client.

Class name:

ServerSocket

Import:

import java.net.*;


Summary of class ServerSocket

Method

Description

Example

Constructors:

 

 

public ServerSocket(int port)

Creates a ServerSocket on the port specified.

ServerSocket ss = new ServerSocket(13);

Object Methods:

 

 

public Socket accept()

Waits until a client connects. Returns a Socket object representing the connection.

Socket s = ss.accept();

public void close()

Closes the ServerSocket. Frees up the port. Note that this is not the same as closing a Socket.

ss.close();

public String toString()

Returns a string which is the number of the local port

String port = ss.toString();


Question: What are the differences between a socket and a server socket?

Informative Demos

  1. If you are using Windows, open the DOS window and type the following to see which of your ports are open:
    netstat -a
    
  2. Go to the following site and ask it to probe your ports:
    www.grc.com
    
  3. Go to this site to see how vulnerable your computer may be:

    privacy.net/analyze
    

Exercises

  1. Run the daytime server given above in the text and test it with either telnet or the daytime client (code given earlier).
  2. You can run the server on one PC, with the client either on the same machine or a different PC. When you run the client program, you can type in localhost as the host name to get the time from.
  3. Augment the daytime server by adding a logging facility, so that it displays in a text area the names of clients who have connected.
  4. Run and test the web server program given in the text, using a telnet program as a client.
  5. Complete the empty methods within the web server (HTTP server) program given in the text. These are skipRemainder(), sendHeader() and fileNotFound().
  6. (Big project) Enhance the web server program with the following facilities: