Out: Sunday, 6 March
Due: Sunday, 13 March, 11:59 pm
Latest Possible Submission Time: Tuesday, 15 March, 11:59 pm
Turnin: Gradescope
You start with code that implements a simple form of web server, written as a single threaded Java program. The web server is very restrictive:
You should convert the implementation to one using multiple threads, so that requests can be handled in any order.
Clients send requests to the server, and receive responses from it, using "sockets." Sockets are network communication endpoints. The server uses two sockets. All requests arriving on one of them are provided DocA, and all requests on the other are provided DocB. (This simplifies the implementation, which never bothers to look at what was sent as the request, since it can be for only one thing.) The accept() call on the server's serversocket returns when a client connects, which is how the server knows that a request has been sent.
The code is divided into HTTPServer and HTTPSocket classes. The HTTPServer is the main control flow. It creates two HTTPSockets and then goes into a loop. During each iteration of the loop, first a method of the DocA socket, then a method of the DocB socket, is invoked to handle an incoming request, then the user is asked to indicate whether or not to terminate the server. We might draw this control flow like this:
You allow arbitrary order of requests by multi-threading the implementation. One thread is dedicated to handling requests on the DocA socket, another thread handles requests on the DocB socket, and the final thread handles user input regarding termination. Because the process starts with a thread (called the main thread), you need to create only two additional threads. The main thread is used to handle user input and server termination. Multithreaded execution might be drawn like this (where dashed lines are thread creation and solid lines are normal control flow):
You should be careful to handle possible race conditions when you multi-thread. The application has been chosen in part because it is naturally free of race conditions, but one has been introduced specifically for the purpose of this homework.
Network communication endpoints use sockets. A socket "is bound to" (is associated with) "a port." A port is named by an integer. For instance, web servers typically listen using a socket bound to port 80.
There can be only one socket bound to a particular port at a time (on a single system). An attempt to bind a second socket to a port number results in an error. This means that we have to be careful to use different port numbers when running on klaatu.
It is a somewhat difficult (and, I hope, interesting) problem how we might agree on who uses what port number in a way that achieves our goals without too much work. I have implemented a heuristic that should be highly likely to avoid conflicts (and resembles things sometimes done in distributed systems). Basically, you should use your student ID to generate two valid port numbers. (Valid port numbers have to be chosen in a restricted range of integers.)
For this to work, you MUST edit the value assigned to variable MYID in HTTPServer.java:
static final int MYID = 1234567; // STEP 1 -- replace with your student ID static final int PORT_A = MYID % (65545-1026) + 1025; static final int PORT_B = PORT_A + 1;
Port conflicts could occur, but you'd have to be very unlucky to experience one.
Edit the code to use Java threads so that the server can handle requests in any order.
There is endless information on the web about Java threads, including endless examples.
A particularly simple example is provided in /courses/cse410/22wi/lect16files on klaatu. It defines a class, Worker, that extends the Java Thread class, and a driver class, Example, that creates two Worker threads, sets them running, and waits for them to complete. Those are the operations you need in this homework.
As always, we welcome questions on the discussion board or to cse410-staff@cs.washington.edu.
Hand in your source code files on gradescope.