Fun With Java Seminar

Homework 6: Client-Server Programming


Contents: [Background and Motivation] [What to Read] [Directions] [The Problems]
Due: We will discuss problems 1-2 on July 25, and the rest (what you can do) on July 29.

Background and Motivation

This homework is designed for you to learn multi-threaded client-server programming in Java using TCP/IP. In this assignment, you will be dealing with most aspects of designing a full-fledged multi-threaded server. As such, this assignment is likely to be complex and require you to understand threads and sockets very well. Nevertheless, I think you will find the additional effort to be fun and well worth the effort.

A server is a program that can compute and render some pictures on a window, where the nature of the picture is given by a set of parameters. A client is a program that can establish a connection with the server and request initiation of one such computation by specifying the values of the parameters. The server may be performing computations on behalf of more than one client, and each such computation will be performed in a separate thread. The exact nature of the computation and the picture rendered is up to you, but we have provided some suggestions for some easy-to-generate pictures that may also look interesting, depending on the values of the parameters.

The server program is initially started. It sets up a TCP server socket and blocks, waiting for incoming connections. (You need to choose an appropriate port number for the server socket -- say 4023.) A client connects to the server, and sends a message

	initiate X Y w other-params
where the meaning of other-params depends on the computation and rendering task performed by the server. X and Y provide the coordinates where the computation is to be started. The nature of the computation must be such that it starts rendering at (X,Y) on the screen, and as the computation progresses, the rendering moves away from this point. The w parameter determines how the screen is overwritten by the computation. In particular, assuming a pixel model for the screen, let v_o be the old value of a pixel, while the current computation computes a new value v_c. Then the new value of the pixel is given by w*v_c + (1-w)*v_o. The parameter w is constrained to be in the range 0 <= w <= 1.

In order to wait for incoming connections, the server program invokes the accept method (look at the java.net package, especially the ServerSocket and SocketImpl classes), which blocks until a client connects to the server. When a client makes a connection, the accept method returns with a new Socket object. This new socket object is to be used for reading the information sent by the client. NOTE that the original socket on which the accept method is invoked is not the same as the socket returned by the accept method. That original socket is set up only to accept connections.

Being a multi-threaded server, you need to ensure that your program always has at least one thread that is able to accept incoming requests. For instance, as soon as an accept method returns, you may spawn a new thread that performs another accept. Alternatively, the new thread spawned can serve the request, while the parent thread performs another accept. In either case, it is the responsibility of the server to respond to the client with an integer identifier for the newly initiated computation, which will be used by the client to perform additional operations on this computation.

Note that since multiple computations can be taking place simultaneously within the server, multiple threads can access and update the screen simultaneously. To ensure correct results, you need to ensure mutual exclusion of these threads when they are in critical sections. For instance, you will use a synchronized method for updating a pixel, which will ensure that the reading of v_o and updating with v_n are done atomically.

Once a computation is started, a client can close down the connection at that point. Alternatively, it may send additional commands to the server to initiate additional computations, or to kill an existing computation, or to request notification under certain conditions. The two new commands have the following forms:

	stop computationId
	notify computationId distance
The first command is used to terminate an existing computation within the server by providing the id of the computation. (Note: a ``computationId'' is used here, because a single client can send multiple ``initiate'' messages to the server on a single connection.) To implement this function in the server, there are two possibilities. In one case, you may use a polling method within the server, wherein the thread perfoming the computation is periodically polling its associated socket to see if the client has requested additional operations to be performed, and perform them as required. The polling mechanism, which is a synchronous mechanism, is simpler to implement, but has the overhead of checking constantly for input. It also gets complicated if the same connection is being used by a client to initiate multiple computations within the server. An alternative approach is to rely on asynchronous mechanisms for communication among threads. In this case, the thread performing the computation is off on its own, and does not check the socket. A separate thread awaits additional messages on the socket. It then communicates with the thread performing the computation using asynchronous mechanisms such as a thread interrupt.

The notify command is used by a client to request that it be notified when the computation reaches a point that is distance pixels away from the point where the computation is started. Implementation of notification also requires inter-thread communication on the server side. The server will send a

	notification computationId
message to the client when the notification condition is met.

Finally, in a server, you are always concerned about resource usage, and in particular, in ensuring that resources are not being wasted. For this purpose, you will terminate any computation as soon as the client that requests the computation disconnects from the server either normally or abnormally. These conditions will typically lead to exceptions on the server side, and you will implement handlers for these exceptions to deal with these conditions. You will also set an upper limit for the time spent on any computation. After this time, the computation is automatically killed, and the server disconnects from the client that requested the computation. Finally, limit the number of active connections to some fixed number k (choose a number around 10) and active computations to a number j > k. Additional client requests will be accepted, but the client will be sent a negative computation id, which indicates that the computation could not be started on the server.

In the simplest case, the server program draws ellipses starting with both axes being of a random size, and the color of the ellipse being a random value. Successive axes and color of the successive ellipses drawn will change gradually, and the center of the ellipse moves away from the origin along some trajectory. (Use a high-degree polynomial or a spiral for the trajectory so as to get interesting patterns.) It is important for the change in size, color and center of the ellipse to change very slowly, so that the picture looks like an animation of an ellipse that wobbles, changes color gradually and moves away.

What to Read

In The Java Programming Language by Arnold and Gosling (Addison-Wesley, 1996) read chapter 9 for information on threads. Or in Just Java by van der Linden (Prentice-Hall, 1997), read the section on threads in chapter 5 (pages 179-205), and chapter 8, especially pages 309-328; you might also want to skim chapter 11. For reference, you may want to refer to chapter 17 of The Java Language Specification by Gosling, Joy, and Steele (Addison-Wesley, 1996).

A description of the Networking Enhancements in JDK 1.1 comes with the JDK 1.1 documentation. This includes information on Extending Sockets in JDK 1.1.

You might also look at the Threads of Control chapter in The Java Tutorial Object-Oriented Programming for the Internet by Mary Campione and Kathy Walrath (Addison-Wesley, 1996).

If this subject interests you, you might want to get the book Concurrent Programming in Java: Design Principles and Patterns by Doug Lea (Addison-Wesley, 1997).

Directions

This homework, like the others in this seminar, will be open-ended and somewhat ill-defined. we'll try to give you some idea of the difficulty/effort involved in each part. Do what you have time for.

Bring a printout of your code to class, and be prepared to discuss it with other people in the class.


Problems

For this homework, please proceed in the following stages, rather than attempting to do every thing in one shot.
  1. Implement the server and client code for sending and receiving messages. Leave the handling of received messages out at this point.
  2. Implement the code for processing the "initiate" message on the server side.
  3. Implement the server code for processing the "stop" message.
  4. Implement the mechanisms for resource usage monitoring and control.
  5. Implement the code for processing "notify" message.

[Back to the Fun with Java Seminar homepage]
Last update: $Date: 1997/07/20 21:35:31 $
R. C. Sekar