Recent Changes - Search:

Network Programming

This website demonstrates using wikis as teaching and learning tool.

The course instructor is happy to share the teaching materials here with those who find it readable.

Tutorial - Java Network Programming - Web Server Example

Introduction

  • In this tutorial, you will experiment with a simple HTTP server implemented using a socket.
  • You will be provided with the source code of this example program.
  • Before you go to compile, run and test the program, let’s have an idea of what an HTTP server basically does.

The HyperText Transfer Protocol

The HyperText Transfer Protocol (HTTP) is the set of rules for transferring files (for example, HTML documents, text, image, sound, video, and other multimedia files) between web clients and web servers. Relative to the TCP/IP suite of protocols, the HTTP is an application-layer protocol. The latest version of HTTP is HTTP 1.1.
HTTP communication can be divided into two separate parts, namely, HTTP requests and HTTP responses.
An HTTP request, which is made by a web client, contains information about a resource on the web server, and the action the client wishes the server to perform on the resource.
A web server fulfils an HTTP request by returning an HTTP response, which varies with the type of request and whether or not the request could be serviced.
To retrieve a web page from a certain HTTP server, an HTTP client simply sends a GET request to the server specifying a particular path and file name. The GET method is one type of requests of the HTTP application-level protocol. For example, the following HTTP request:
      GET /index.html HTTP/1.0
tells the server that the client wants to get the file /index.html and that this is an HTTP version 1.0 request. The server will reply by sending the HTTP response header fields, followed by the file to the client, or an error message if it cannot provide the requested file.
The server’s reply contains the HTTP response code and description, possibly HTTP headers and content of the file. An example of an HTTP response is:
      HTTP/1.0 200 OK
      Content-Type: text/html
      <HTML lang="zh">
      [ … other content of HTML file … ]
In the first line of the above response, the number 200 is the response code (or status code) and the text ‘OK’ is the description of the code. Common HTTP response codes and their descriptions include:
  • 200 — OK
  • 400 — Bad Request
  • 404 — Not Found
  • 500 — Internal Server Error
There are many types of HTTP headers in a response. The headers are optional. One important type of headers is the content type, or MIME type. It specifies how the content that follows the headers is dealt with by the Web client. For example, a Web browser interprets content of type ‘text/html’ as a webpage and that of type ‘image/gif’ as a GIF image.
After the headers is an empty line, followed by the response body. In the above HTTP response, the response body is the content of the HTML file requested by the Web browser.
HTTP GET transaction (Source: http://oreilly.com/openbook/webclient/ch03.html)

Task 1: Compile the following Web Server program

  1. import java.io.BufferedOutputStream;
  2. import java.io.BufferedReader;
  3. import java.io.File;
  4. import java.io.FileInputStream;
  5. import java.io.IOException;
  6. import java.io.InputStream;
  7. import java.io.InputStreamReader;
  8. import java.io.OutputStream;
  9. import java.net.ServerSocket;
  10. import java.net.Socket;
  11. import java.util.HashMap;
  12. import java.util.Map;
  13. import java.util.concurrent.ExecutorService;
  14. import java.util.concurrent.Executors;
  15. import java.util.logging.Level;
  16. import java.util.logging.Logger;
  17.  
  18. public class WebServer {
  19.  
  20.     private static Logger logger = Logger.getLogger("WebServer");
  21.  
  22.     private static Map<String, String> contentTypes;
  23.     private static Map<Integer, String> httpResponses;
  24.     static {
  25.         contentTypes = new HashMap<String, String>();
  26.         contentTypes.put(".htm", "text/html");
  27.         contentTypes.put(".html", "text/html");
  28.         contentTypes.put(".txt", "text/plain");
  29.         contentTypes.put(".jpg", "image/jpeg");
  30.         contentTypes.put(".gif", "image/gif");
  31.         contentTypes.put(".png", "image/png");
  32.         contentTypes.put("", "application/octet-stream");
  33.  
  34.         httpResponses = new HashMap<Integer, String>();
  35.         httpResponses.put(200, "OK");
  36.         httpResponses.put(400, "Bad Request");
  37.         httpResponses.put(404, "Not Found");
  38.         httpResponses.put(500, "Internal Server Error");
  39.     }
  40.  
  41.     static String getResponseLine(int responseCode) {
  42.         return responseCode + " " + httpResponses.get(responseCode);
  43.     }
  44.     static String getContentType(File file) {
  45.         int pos = file.getName().lastIndexOf('.');
  46.         String ext = pos >= 0 ? file.getName().substring(pos) : "";
  47.         String type = contentTypes.get(ext);
  48.         if (type == null)
  49.             type = contentTypes.get(""); // default
  50.         return type;
  51.     }
  52.  
  53.     /** An HTTP exception, e.g., invalid request, file not found, etc */
  54.     static class HttpException extends RuntimeException {
  55.         public HttpException(int responseCode) {
  56.             super(getResponseLine(responseCode));
  57.         }
  58.     }
  59.  
  60.     /** Handler for an individual client */
  61.     static class ClientHandler implements Runnable {
  62.         private Socket socket;
  63.         private String docBase;
  64.  
  65.         ClientHandler(Socket socket, String docBase) {
  66.             this.socket = socket;
  67.             this.docBase = docBase;
  68.         }
  69.  
  70.         /** Perform echoing to the client socket */
  71.         public void run() {
  72.             OutputStream os = null;
  73.             try {
  74.                 os = socket.getOutputStream();
  75.                 String requestName = parseHttpRequest(socket.getInputStream());
  76.                 File requestFile = new File(docBase, requestName);
  77.                 if (! requestFile.getCanonicalPath().startsWith(docBase))
  78.                     throw new HttpException(404);
  79.                 if (! requestFile.isFile() || ! requestFile.canRead())
  80.                     throw new HttpException(404);
  81.                 sendHttpResponse(os, getResponseLine(200), requestFile);
  82.             } catch (HttpException ex) {
  83.                 sendHttpResponse(os, ex.getMessage(), null);
  84.             } catch (IOException ex) {
  85.                 logger.log(Level.SEVERE, null, ex);
  86.             } finally {
  87.                 try {
  88.                     socket.close();
  89.                 } catch (IOException ex) {
  90.                     logger.log(Level.SEVERE, null, ex);
  91.                 }
  92.             }
  93.         }
  94.  
  95.         /** Parse input stream and return the URL */
  96.         private String parseHttpRequest(InputStream is) {
  97.             try {
  98.                 BufferedReader reader =
  99.                         new BufferedReader(new InputStreamReader(is));
  100.                 String str = reader.readLine(); // maybe IOExecption
  101.                 logger.info("Request: \"" + str + "\" from " +
  102.                         socket.getInetAddress() + ":" + socket.getPort());
  103.                 String[] tokens = str.split("\\s+"); // maybe NullPointerEx
  104.                 if (tokens.length < 2 || ! tokens[0].equals("GET"))
  105.                     throw new HttpException(400); // bad request
  106.                 String file = tokens[1];
  107.                 if (file.endsWith("/")) // trailing /
  108.                     return file + "index.html";
  109.                 else
  110.                     return file;
  111.             } catch (Exception ex) {
  112.                 throw new HttpException(400); // bad request
  113.             }
  114.         }
  115.  
  116.         private static final String CRLF = "\r\n"; // newline
  117.  
  118.         /** Send the HTTP response, possibly with a file's content */
  119.         private void sendHttpResponse(OutputStream os, String line, File file) {
  120.             try {
  121.                 logger.info("Response: \"" + line + "\" to " +
  122.                         socket.getInetAddress() + ":" + socket.getPort());
  123.                 BufferedOutputStream bos = new BufferedOutputStream(os);
  124.                 String str = "HTTP/1.0 " + line + CRLF;
  125.                 bos.write(str.getBytes());
  126.                 if (file == null) {
  127.                     str = "Content-Type: text/plain" + CRLF + CRLF + line;
  128.                     bos.write(str.getBytes());
  129.                 } else {
  130.                     String type = getContentType(file);
  131.                     str = "Content-Type: " + type + CRLF + CRLF;
  132.                     bos.write(str.getBytes());
  133.                     // transmit the file
  134.                     byte[] buffer = new byte[1024];
  135.                     int nRead;
  136.                     InputStream is = new FileInputStream(file);
  137.                     while ((nRead = is.read(buffer)) >= 0)
  138.                         bos.write(buffer, 0, nRead);
  139.                     is.close();
  140.                 }
  141.                 bos.flush();
  142.             } catch (IOException ex) {
  143.                 logger.log(Level.SEVERE, null, ex);
  144.             }
  145.         }
  146.     }
  147.  
  148.     public static void main(String[] args) {
  149.         int port = args.length > 0 ? Integer.parseInt(args[0]) : 80;
  150.         String docBase = args.length > 1 ? args[1] : "./html";
  151.         try {
  152.             docBase = new File(docBase).getCanonicalPath();
  153.             ServerSocket server = new ServerSocket(port);
  154.             logger.info("Server started, docBase at " + docBase
  155.                     + ", listening at port " + port + " ...");
  156.             ExecutorService executor = Executors.newCachedThreadPool();
  157.             while (true) {
  158.                 Socket socket = server.accept();
  159.                 ClientHandler handler = new ClientHandler(socket, docBase);
  160.                 executor.execute(handler);
  161.             }
  162.         } catch (IOException ex) {
  163.             logger.log(Level.SEVERE, null, ex);
  164.         }
  165.     }
  166. }
  • Compile the program and put the Java byte codes to c:\tmp

Task 2: Prepare some simple web pages and images for the web server

  • Make a new directory named html within the c:\tmp
  • Store an image in the created directory
  • Store a simple index.html in the created directory. You can use the following code if you don't have any.
<!DOCTYPE HTML PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Network Programming</title>
<style type="text/css" media="screen">
body {background-color:#87b2d5; text-align:center; color:#fff;font-family:Georgia, "Times New Roman", Times, serif;}
p {margin:135px 0 35px 0; font-size:80px;}
#countdown1 a {font-size:50px; text-decoration: none; color:#a4c7e4;}
</style>
</head>
<body>
<p>ouhk.edu.hk</p>
<div id="countdown1"><a href="#">Network Programming</a></div>
</body>
</html>

Task 3: Test the Web Server program

  • Run the server program
  • Use a browser to test the Web server. For example, you can enter the following URL:
    http://localhost/sample.jpg
    http://localhost/indxe.html
  • What will happen if the server cannot find a file that the client request?

Questions

  • What statement(s) tell the location of the files that the server can retrieve?
  • Can you change the port number for the Web server? If yes, how?
  • Find the statement that creates the ServerSocket for the server.
  • Find the statement that creates the Socket for each client connection.

Submission

  • Please submit your work to Steven by email.
Edit - History - Print - Recent Changes - Search
Page last modified on October 14, 2009, at 05:36 PM