Contact:
Olivier Gruber (olivier.gruber@inrialpes.fr)
Fabienne Boyer (fabienne.boyer@inrialpes.fr)
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.
Java 2 SDK.
Either IDE (e.g. Eclipse) or java tools directly (javac, make, java, and jdb).
We strongly recommend using Eclipse, development and debugging is greatly simplified.
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
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
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
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:
Client side:
The client connects to the server.
Sends it a request which contains the name of the requested file.
Stores the received file locally on disk.
Server side:
The server waits, on a given port number, for connections from remote clients.
When receiving a client request, the server returns the corresponding file to the client.
Define your file-transfer protocol over TCP/IP that includes the following:
Format of the request and response for a given file.
Pay attention to the encoding of your primitive types and strings.
Remember to handle errors on the server side, such as file not found. Send an error code back to the client.
Pay attention to connection failures on both sides, reasons may be failed servers or failed clients. A client may fail or be interrupted during its download.
Write the server program that is launched as
follows:
TP1> java org.load.distsyst.tp1.Server
<port-number> <folder>
where
port-number is the port on which the server is launched
folder is the folder which contains accessible files
Write the client program that is launched as
follows:
TP1> java org.load.distsyst.tp1.Client
<server name> <server port> <wanted file>
Run the Server and Client programs on two different Java Virtual Machines, but on the same host (machine).
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.
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
port-number is the port on which the server is launched
backlog is an optional parameter that specifies the maximum open connections on the server.
folder is the folder which contains accessible files
You must still resist communication failures, server failures, worker failures, and client failures.
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.
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:
Faster downloads.
Tolerate better server and communication failures.
Follow these steps
Revisit your file-transfer protocol from TCP/IP to UDP.
Assume that your request is small and fits in one datagram packet.
Returned files may be of any size, smaller or larger than a datagram packet.
Pay attention that packets may be lost.
You have to resist such failures.
How do you resist communication failures efficiently?
How do you resist server failures? We assume that a failed server recovers.
Pay attention that packets may be reordered.
How do you improve performance over TCP/IP?
Modify both you client and server to use sockets over UDP.
Test you client and server
With short and large files.
With large files, you must be able to kill the server during the transfer and restart it, without your client failing and without the on-going file transfer failing.
[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/