The aim of this exercise is to write a server for the IdUpperCase
protocol.
IdUpperCase
long
in BigEndian identifying the request,
UTF-8
.
For the servers, we will no longer write everything in the main
method. A server will be an object of the class ServerIdUpperCaseUDP
:
serve
binds a DatagramChannel
to this port and treats the packets received.
main
parses the command line arguments, create a new server object and calls its method serve
.
Write a class ServerIdUpperCaseUDP
which takes as argument the port of the server.
Test your class with the client you have written in the previous session.
$ java fr.uge.net.udp.ServerIdUpperCaseUDP 4545
If you still have not finished your client, you can use this client ClientIdUpperCaseUDP.jar.
The aim of this exercise is to write a service to perform sum of an arbitrary number of long integers. The client has a list of longs integers which he wants to sum. He will send each long in a different packet to the server. The server will sum the longs and send back the sum to the client.
This protocol is stateful and the server will need to store the informations received from the different clients (identified by the IP address + port number).
The protocol (we describe in detail below) is designed to handle several problems:
We now give a detailed presentation of the different packets involved in protocol. All the fields marked as long are signed eight bytes integers in BigEndian. Each packet will start by a byte coding its type. This byte is equal to:
OP = 1
if the packet contains an operand sent from the client to the server.byte long long long long +---+-----------+-----------+-----------+-----------+ | 1 | sessionID | idPosOper | totalOper | opValue | // packet OP +---+-----------+-----------+-----------+-----------+where
sessionID
is a unique session identifier chosen by the client and common to all
the packets related to a given sum,idPosOper
is the index (or position) of the operand in the sum (this value belongs to the interval [0 .. totalOper-1]
)totalOper
is the total number of operand in the sum,opValue
is the value of the operand.ACK = 2
if the packet is an acknowledgment sent by the server to the client in response to a OP
packet.byte long long long +---+-----------+-----------+ | 2 | sessionID | idPosOper | // packet ACK +---+-----------+-----------+where
sessionID
is the session identifier (the same as the corresponding OP packet),idPosOper
is the index of the acknowledged operand.RES = 3
if the packet contains the value of the sum of all the operands.
The server sends such RES
packet in response to any OP
packet as soon
as the server has received all the operands of the sum (identified by a sessionId). The server
also sends the ACK
packet for the OP
packet.
In this case, the RES
packet has the following format:
byte long long +---+-----------+-----------+ | 3 | sessionID | sum | // packet RES +---+-----------+-----------+where
sessionID
is the session identifier,sum
is the value of the sum of all of the operands (for this sessionID). Let us take the example of a client Charlie (C) who wants to send the longs (operands) 10000, 2000 and 300000 to a server called Serge (S) using our protocol. Charlie will use the session identifier
5555 for this sum.
Charlie will send his 3 operands, in 3 different packets:
+-----+-----------+-----------+-----------+-----------+ | 1 | 55555 | 0 | 3 | 10000 | // C -> S OP 0 +-----+-----------+-----------+-----------+-----------+ OP sessionID idPosOper totalOper opValue +-----+-----------+-----------+-----------+-----------+ | 1 | 55555 | 1 | 3 | 2000 | // C -> S OP 1 +-----+-----------+-----------+-----------+-----------+ OP sessionID idPosOper totalOper opValue +-----+-----------+-----------+-----------+-----------+ | 1 | 55555 | 2 | 3 | 300000 | // C -> S OP 2 +-----+-----------+-----------+-----------+-----------+ OP sessionID idPosOper totalOper opValueNow assume that Serge only receives the packets 1 and 2 (the packet 0 is lost!); Serge will send back two acknowledge packets:
+-----+-----------+-----------+ | 2 | 55555 | 1 | // S -> C ACK 1 +-----+-----------+-----------+ ACK sessionID idPosOper +-----+-----------+-----------+ | 2 | 55555 | 2 | // S -> C ACK 2 +-----+-----------+-----------+ ACK sessionID idPosOperBut the acknowledgement 2 is lost and Charlie only receives the acknowledgement for the packet 1. After a fixed delay, Charlie decides to send again the operand 0 and 2 for which he has not received an acknowledgement:
+-----+-----------+-----------+-----------+-----------+ | 1 | 55555 | 0 | 3 | 10000 | // C -> S OP 0 +-----+-----------+-----------+-----------+-----------+ OP sessionID idPosOper totalOper opValue +-----+-----------+-----------+-----------+-----------+ | 1 | 55555 | 2 | 3 | 300000 | // C -> S OP 2 +-----+-----------+-----------+-----------+-----------+ OP sessionID idPosOper totalOper opValueThis time, Serge receives both packets, he only adds to the sum the first one because the second one was previously received and was already taken into account. Still he sends the acknowledgement packets for both packets:
+-----+-----------+-----------+ | 2 | 55555 | 0 | // S -> C ACK 0 +-----+-----------+-----------+ ACK sessionID idPosOper +-----+-----------+-----------+ | 2 | 55555 | 2 | // S -> C ACK 2 +-----+-----------+-----------+ ACK sessionID idPosOperfurthermore, now that Serge has the 3 required operands (thanks to
totalOper
), he also send a
packet giving the result of the sum.
+----+-----------+-----------+ | 3 | sessionID | 312400 | // S -> C RES 312400 +----+-----------+-----------+ RES sessionID sumIf Charlie receives both acknowledgements, he knows for sure that all operands are now known by Serge. But even if he does not receive the acknowledgment 0 (which might be lost), he can stop as soon as he receives the
RES
packet which contains the final answer.
However, if Charlie has received all the acknowledgments but not the RES
packet (after some time), he can guess that the RES
packet has been lost. He will need to send an OP
packet for any operand to trigger the resent by Serge of the RES
packet.
Write a server ServerLongSum
for this protocol using the same template as in the previous exercise.
To test that your server behaves correctly, you can use the following program ValidatorLongSumUDP.jar. This program tests your server by simulating several clients.
In three different terminals, simultaneously visible on screen, run the three programs:
$ java fr.uge.net.udp.ServerLongSumUDP 7777 $ java -jar UDPProxy.jar 6666 localhost 7777 $ java -jar ValidatorLongSumUDP.jar localhost 6666
If everything is correct, you should see:
Trying 5 queries one after the other. Query 1 succeeded! Query 2 succeeded! Query 3 succeeded! Query 4 succeeded! Query 5 succeeded! Trying 5 queries from the same client at the same time. Test passed Trying 5 clients at the same time. Test passed
Currently your server stores in a HashMap all the data of all the sums it ever performed. In the long run, this will pose a memory problem.
What ressources can be freed when the RES
packet is sent ? Is it possible to remove all the informations related to this sum from the HashMap of the server.
A first possible solution to help the server free its ressources consists in modifying the protocol to allow the client to signal that the server can free the ressources corresponding to a sum. For this, we need to introduce two new packet types.
CLEAN = 4
are sent
by the client to the server to signal that this session will no longer
be used:
CLEAN
packet has the following format:
byte long +---+-----------+ | 4 | sessionID | // packet CLEAN +---+-----------+where
sessionID
is the session identifier.ACKCLEAN = 5
are sent by the server as acknowledgements to the CLEAN
packets.
ACKCLEAN
packet has the following format:
byte long +---+-----------+ | 5 | sessionID | // packet ACKCLEAN +---+-----------+where
sessionID
is the session identifier.Modify your server to handle this extended protocol.
To test your server, you can use the following progam ClientFreeLongSum.jar. This program tests your server by simulating several clients.
In 3 different terminals (on the same screen), launch the 3 programs below:
$ java fr.uge.net.udp.ServerFreeLongSumUDP 7777 $ java -jar UDPProxy.jar 6666 localhost 7777 $ java -jar ClientFreeLongSumUDP.jar localhost 6666
This modification is not sufficient because it assumes that the client respects the protocol.
It would be easy for someone to start a lot of sums on your server and never send any CLEAN
packet. We need a mechanism to deal with this ill-intentionned clients. The solution is to give a time limit for each sum. In other terms, if no packet concerning a given sum are received over a given period of time (for instance 5 minutes) then this sum can be discarded by the server.
Implement this mecanism on your server.