In this series of exercices, you are going to write more and more sophisticated blocking TCP servers for the LongSum protocol.
long integers using the following TCP protocol:
IterativeLongSumServer which treat its clients one after the other.OnDemandLongSumServer which starts a new thread to treat each new client.BoundedOnDemandLongSumServer server which starts a new thread for each client but which limits the number of clients which are simultaneously connected.FixedPreStartedLongSumServer which pre-starts a fixed number of threads which each are going to treat client in a loop. As opposed to the previous exerices, these threads are reused to treat multiple clients one after the other.FixedPreStartedLongSumServer with an interactive console and the with the ability to automatically disconnect inactive clients.
The first verion of the server, IterativeLongSumServer,
simply accepts a client, treat its requests (i.e., there might be
several sums) and when the client closes the connexion, the server
accepts a new client and so on ...
To write this server, you will use the template
IterativeLongSumServer.java.
The full treatment of the connexion with a client is performed by the method serve(SocketChannel client). Exceptions raised during the method serve are thrown and are handled in the launch method.
Write the code for the serve method.
You can test your server using the client ClientLongSum you wrote during the previous session.
% java fr.upem.net.tcp.IterativeLongSumServer 7777 % java fr.upem.net.tcp.ClientLongSum localhost 7777
You must also test using the jar file ClientLongSumVerbose.jar, which connects to the server and sends 5 sums waiting in between sums a delay taken as a parameter on the command line.
% java -jar ClientLongSumVerbose.jar 7777 % java fr.upem.net.tcp.ClientLongSum localhost 7777 100
Until now, you only tested your server with one client. Open 4 terminals. In one of them, launch your server and the 3 others launch
de>ClientLongSumVerbose.jar with a large delay (for instance 5000) as in the image below:
Explain how 3 clients can connect simultaneously to your server despite the fact that your server only treats one client at the time.
We now want to allow several clients to simultaneously connect to the server. For this, we are going to create a new thread to treat each new client.
A first method, quite easy to implement, consists in simply creating a new thread each time a new client is accepted and use this thread to treat the client.
Using the same template as for IterativeLongSumServer, write a new class
OnDemandConcurrentLongSumServer.
You can monitor the number of threads used by your
server using jconsole. You should see that the number
of threads increases with each new connected client.
The problem with this approach is that the number of threads started by the server is unbounded. This means that the server can crash under the load if too many clients connect at the same time.
We now want to write a class BoundedOnDemandConcurrentLongSumServer which ensures that the number of threads concurrently started is at most maxClient (an argument taken from the command line).
Semaphore. The
class Semaphore is thread-safe. An object of the class Semaphore is created with a certain amount of permits.
Semaphore semaphore = new Semaphore(nbPermits);The
semaphore.acquire() method tries to take a permits from the semaphore if there is one and otherwise it blocks until a permits becomes available. The semaphore.release() method put a permit back in the semaphore.
We write the class BoundedOnDemandConcurrentLongSumServer.
The main problem with the solution proposed in the previous exercise is that each time a client is accepted a new thread needs to be started before the client can be treated.
The idea we are going to explore in this exercise is to start
(when the server is launched) a fixed number of threads which will each act as an iteratif serveur (cf. Exercice 1). The mutual exclusion between these worker threads is ensured by the call to
serverSocketChannel.accept() (which is thread-safe).
Write a server
FixedPrestartedLongSumServer which implements this idea. The server will take on the command line the number maxClientsof worker threads.
What happens to the clients who attempt to connect to your server when maxClient are already connected ?
In this exercise, we are going to see how to handle inactive clients in a FixedPreStarted server. Indeed these clients are taking ressources from the server.
The problem with detecting inactive clients is that the method
socketChannel.read and socketChannel.write are blocking. Hence if a worker thread calls socketChannel.read
and the client does not write anything, the worker thread is blocked for ever.
Hence we will need to start a new thread (one for the server) which will have the task of disconnecting inactive clients.
There are two main problems to solve:
To solve these two problems, you can implement a class ThreadData which is threadsafe and which implements following two methods:
setSocketChannel(SocketChannel client) which sets the
socketChannel;tick() which indicates that the client is active;closeIfInactive(int timeout) which disconnect the client
if it has not been active in the past timeout milliseconds;close() which disconnect the client.There will one ThreadData object for each worker thread. A unique thread while call the method closeIfInactive(int timeout) on each of the threadData objects every timeout milliseconds.
The easiest way to code the class ThreadData is to store the SocketChannel of the current client and a long corresponding to the time (obtained with System.currentTimeMillis()) of the last activity.
Starting with the class FixedPrestartedConcurrentLongSumServer, write a class FixedPrestartedConcurrentLongSumServerWithTimeout which properly handles inactive clients.
To test your code, you can use:
% java -jar ClientLongSumVerbose.jar localhost 7777 10000 % java -jar ClientLongSumVerbose.jar localhost 7777 1000 % java fr/upem/net/tcp/FixedPreStartedLongSumServerWithTimeout 7777If the timeout of your server is of 2000 milliseconds, the first
ClientLongSumVerbose should be disconnected by the server
(and hence raise en IOException) but the second ClientLongSumVerbose should not be affected.
On souhaite maintenant rajouter une console au serveur: c'est-à-dire la possibilité de lire des instructions au clavier.
Votre console devra reconnaître trois instructions:
Rajouter une console à votre serveur
FixedPrestartedConcurrentLongSumServerWithTimeout de l'exercice précédent.