ONJava.com -- The Independent Source for Enterprise Java
oreilly.comSafari Books Online.Conferences.

advertisement

AddThis Social Bookmark Button

How Java Web Servers Work
Pages: 1, 2, 3

The ServerSocket Class

The Socket class represents a "client" socket; a socket that you construct whenever you want to connect to a remote server application. If you want to implement a server application, such as an HTTP server or an FTP server, you need a different approach. This is because your server must stand by all the time, as it does not know when a client application will try to connect to it.



For this purpose, you need to use the java.net.ServerSocket class. This is an implementation of a server socket. A server socket waits for a connection request from a client. Once it receives a connection request, it creates a Socket instance to handle the communication with the client.

To create a server socket, you need to use one of the four constructors the ServerSocket class provides. You need to specify the IP address and port number on which the server socket will listen. Typically, the IP address will be 127.0.0.1, meaning that the server socket will be listening on the local machine. The IP address the server socket is listening on is referred to as the binding address. Another important property of a server socket is its backlog, which is the maximum queue length for incoming connection requests before the server socket starts to refuse incoming requests.

One of the constructors of the ServerSocket class has the following signature:

public ServerSocket(int port, int backLog, InetAddress bindingAddress);

For this constructor, the binding address must be an instance of java.net.InetAddress. An easy way to construct an InetAddress object is by calling its static method getByName, passing a String containing the host name:

InetAddress.getByName("127.0.0.1");

The following line of code constructs a ServerSocket that listens on port 8080 of the local machine with a backlog of 1.

new ServerSocket(8080, 1, InetAddress.getByName("127.0.0.1"));

Once you have a ServerSocket instance, you can tell it to wait for incoming connection requests by calling the accept method. This method will only return when there is a connection request. It returns an instance of the Socket class. This Socket object can then be used to send and receive byte streams from the client application, as explained in the The Socket Class. Practically, the accept method is the only method used in the application accompanying this article.

Source Code

Download the HowWebServersWork.zip file for the example application.

The Application

Our web server application is part of the ex01.pyrmont package and consists of three classes:

  • HttpServer
  • Request
  • Response

The entry point of this application (the static main method) is in the HttpServer class. It creates an instance of HttpServer and calls its await method. As the name implies, await waits for HTTP requests on a designated port, processes them, and sends responses back to the clients. It keeps waiting until a shutdown command is received. (The method name await is used instead of wait because wait is an important method in the System.Object class for working with threads.)

The application only sends static resources, such as HTML and image files, from a specified directory. It supports no headers (such as dates or cookies).

We'll now take a look at the three classes in the following subsections.

The HttpServer Class

The HttpServer class represents a web server and can serve static resources found in the directory indicated by the public static final WEB_ROOT and all subdirectories under it. WEB_ROOT is initialized as follows:

public static final String WEB_ROOT =
	System.getProperty("user.dir") + File.separator  + "webroot";

The code listings include a directory called webroot that contains some static resources that you can use for testing this application. You can also find a servlet that will be used for my next article, "How Servlet Containers Work."

To request a static resource, type the following URL in your browser's Address or URL box:

http://machineName:port/staticResource

If you are sending a request from a different machine from the one running your application, machineName is the name or IP address of the computer running this application. If your browser is on the same machine, you can use localhost for the machineName. port is 8080 and staticResource is the name of the file requested and must reside in WEB_ROOT.

For instance, if you are using the same computer to test the application and you want to ask the HttpServer to send the index.html file, use the following URL:

http://localhost:8080/index.html

To stop the server, send a shutdown command from a web browser by typing the pre-defined string in the browser's Address or URL box, after the host:port section of the URL. The shutdown command is defined by the SHUTDOWN static final variable in the HttpServer class:

private static final String SHUTDOWN_COMMAND = "/SHUTDOWN";

Therefore, to stop the server, you can use:

http://localhost:8080/SHUTDOWN

Now, let's have a look at the await method that is given in Listing 1.1. The explanation of the code is to be found right after the listing.

Listing 1.1. The HttpServer class' await method

public void await() {
    ServerSocket serverSocket = null;
    int port = 8080;
    try {
        serverSocket =  new ServerSocket(port, 1,
        InetAddress.getByName("127.0.0.1"));
    }
    catch (IOException e) {
        e.printStackTrace();
        System.exit(1);
    }

    // Loop waiting for a request
    while (!shutdown) {
        Socket socket = null;
        InputStream input = null;
        OutputStream output = null;
        try {
            socket = serverSocket.accept();
            input = socket.getInputStream();
            output = socket.getOutputStream();

            // create Request object and parse
            Request request = new Request(input);
            request.parse();

            // create Response object
            Response response = new Response(output);
            response.setRequest(request);
            response.sendStaticResource();

            // Close the socket
            socket.close();

            //check if the previous URI is a shutdown command
            shutdown = request.getUri().equals(SHUTDOWN_COMMAND);
        }
        catch (Exception e) {
            e.printStackTrace();
            continue;
        }
    }
}

The await method starts by creating a ServerSocket instance and then going into a while loop.

serverSocket =  new ServerSocket(
     port, 1, InetAddress.getByName("127.0.0.1"));

...

// Loop waiting for a request
while (!shutdown) {
    ...
}

The code inside of the while loop stops at the accept method of ServerSocket, which returns only when an HTTP request is received on port 8080:

socket = serverSocket.accept();

Upon receiving a request, the await method obtains the java.io.InputStream and the java.io.OutputStream objects from the Socket instance returned by the accept method.

input = socket.getInputStream();
output = socket.getOutputStream();

The await method then creates a Request object and calls its parse method to parse the raw HTTP request.

// create Request object and parse
Request request = new Request(input);
request.parse();

Next, the await method creates a Response object, sets the Request object to it, and calls its sendStaticResource method.

// create Response object
Response response = new Response(output);
response.setRequest(request);
response.sendStaticResource();

Finally, the await method closes the Socket and calls the getUri method of Request to check if the URI of the HTTP request is a shutdown command. If it is, the shutdown variable is set to true and the program exits the while loop.

// Close the socket
socket.close();
//check if the previous URI is a shutdown command
shutdown = request.getUri().equals(SHUTDOWN_COMMAND);

Pages: 1, 2, 3

Next Pagearrow