Introduction to Distributed Systems

Dept. of Computer Science
ENSIMAG - INPG - France

Contact:


Programming distributed systems with Java Sockets

The objectives of this work study is to master basic techniques for building distributed systems. We will use a classical client/server architecture, using Java sockets as our communication layer. We will use both TCP/IP and UDP, getting a feel for the pros and cons. We will also touch on the design of multi-threaded servers. Throughout the study, we will consider failures, what they can be and what can be done to resist them.

2. Software environment

Use the following software

We strongly recommend using Eclipse, development and debugging is greatly simplified.

How to compile a Java program

Type the following command line:

TP1> javac -d classes src/*.java

If your program uses a Java library (e.g. lib1.jar), type the following command line:

TP1> javac -classpath .:classes:lib/lib1.jar -d classes src/*.java

How to run a Java program

If your program's main Java class is C1, type the following command line:

TP1> java -classpath .:classes C1

If your program uses a Java library (e.g. lib1.jar), type the following command line:

TP1> java -classpath .:classes:lib/lib1.jar C1

How to generate a Java doc

Type the following command line:

TP1> javadoc -d doc -sourcepath src

More details on Java tools can be found in Sun Microsystems' web site: http://java.sun.com/j2se/1.5.0/docs/tooldocs


Part I: A basic client/server distributed system

We consider a distributed system consisting of a (simple) file server. Clients remotely access this service to download files. We will use sockets over TCP/IP. The client-server interaction can be sketched as follows:

Follow these steps:

  1. Define your file-transfer protocol over TCP/IP that includes the following:

  1. Write the server program that is launched as follows:

    TP1> java org.load.distsyst.tp1.Server <port-number> <folder>

    where

  2. Write the client program that is launched as follows:

    TP1> java org.load.distsyst.tp1.Client <server name> <server port> <wanted file>

  3. Run the Server and Client programs on two different Java Virtual Machines, but on the same host (machine).


Part II: A multi-threaded server

In the previous version of the server program, the server is only able to handle one client request at a time. In this second part, our server must be able to satisfy multiple clients simultaneously. One way is to create one thread per request. Unfortunately, this dynamic thread creation is time-consuming and will impact the server performance, yielding longer response times than necessary.

A commonly used technique to improve server performance is multi-threading via a pool of threads. A pool of threads is created when the server is launched. Each time a client sends a request to the server, the server delegates the processing of that request to one of the threads available in its pool of threads. When the thread finishes processing that request, it waits again for new client requests. Java concurrency tutorial may be an helpful guide.

Basic Design:

We will use a fixed size pool of threads and shared buffer between the server thread and slave threads. The server thread writes client requests to the shared buffer, and the slave threads read those requests from the buffer in order to process them (this is know as the Producer/Consumer pattern). For each request, the slave thread processing it answers directly to the corresponding client.

You will use the same client program to request a download. Write the server program that is launched as follows:


TP1> java org.load.distsyst.tp1.ThreadedServer <port-number> <backlog> <folder>


where

You must still resist communication failures, server failures, worker failures, and client failures.

Extended Design:

We will make two extensions to our multi-threaded design.

First, we will consider long downloads, which may fail. Propose a solution based on the principle of splitting the downloads of large files into smaller downloads that are more likely to succeed. In case of failure, ensure that you restart from the last small download that failed.

Second, we will consider that some files are hot (requested often). Insert a file cache in your server to retain the most recently downloaded files in memory.




Optional Part III: From TCP/IP to UDP

UDP Protocol:

Moving from TCP/IP to UDP, the properties of the socket change. TCP/IP is lossless and FIFO, giving you a real infinite stream. UDP is packet-oriented, called datagram packets. Datagram packets may be lost or re-ordered. Nevertheless, we can build a more efficient and more resilient file transfer protocol:

Follow these steps

  1. Revisit your file-transfer protocol from TCP/IP to UDP.

  2. Modify both you client and server to use sockets over UDP.

  3. Test you client and server


References

[Sun07] The Java tutorials Lesson: Concurrency
http://java.sun.com/docs/books/tutorial/essential/concurrency/index.html

[Mahmoud96] Q. H. Mahmoud. Sockets programming in Java: A tutorial. JavaWorld.com, 12/11/96. http://www.javaworld.com/javaworld/jw-12-1996/jw-12-sockets.html

[Sun07] Sun Microsystems. JavaTM 2 Platform Standard Edition 5.0 - API Specification. http://java.sun.com/j2se/1.5.0/docs/api/