:: Enseignements :: ESIPE :: E4INFO :: 2013-2014 :: Applications réseaux ::
![[LOGO]](http://igm.univ-mlv.fr/ens/resources/mlv.png) |
Serveur UDP, Tolérance aux pertes
|
Exercice 1 - Longue Somme de Long
On souhaite mettre en place une sorte de calculette permettant à un client
de demander à un serveur le résultat de la somme de plusieurs nombres qui
sont des entiers long (sur 8 octets).
Le "protocole" convenu établit que pour cela, le client doit envoyer chaque
opérande, un par un, big endian.
Le résultat de la somme totale sera renvoyé par le serveur
à la fin de la réception des opérandes, qui est signalée par la première opérande nulle
(i.e. 0) reçue du client.
Le fichier
ClientLongSumDummy.java contient un client trés simple qui envoie succéssivement tous les
long d'une liste et attend la réponse du serveur avec un timeout d'une seconde.
Vous pouvez le lancer en donant en argument l'adresse et le port du serveur:
$java ClientLongSumDummy localhost 7777
- Implémenter un serveur qui rend ce service de
en supposant qu'un seul client l'utilise à la fois.
En particulier, on ne se souciera pas de la source des paquets.
-
Tentez alors d'utiliser plusieurs clients simultanément avec le même serveur.
Que constatez vous? Comment l'expliquer?
- On souhaite maintenant rendre le serveur capable de traiter correctement
plusieurs clients simultaménement. Proposez une implémentation. Vous suivrez le template ServerLongSumDummyTemplate.java
-
En UDP les paquets peuvent être perdus et l'ordre d'émission n'est pas
nécessairement celui de réception. Par exemple, si vous envoyez des paquets
contenant les valeurs 1,2,3,4 et 5. Le serveur pourra recevoir dans l'ordre
2,1,5. Les paquets contenant 3 et 4 ont été perdus.
Ce comportement se produit rarement sur un réseau local.
Le programme
UDPProxy.jar
va nous permettre de le simuler sur votre machine.
UDPProxy est un proxy UDP qui va perdre un certain
pourcentage des paquets et qui va échanger aléatoirement l'ordre des paquets.
Pour l'utiliser, lancez dans trois shell différents les trois applications suivantes:
$ java upem.net.udp.LongSumServer 7777
$ java -jar UDPProxy.jar 5555 localhost 7777 -long
$ java upem.net.udp.LongSumClient localhost 5555
Dans cet example, UDPProxy écoute sur le port 5555 et
renvoie les paquets vers localhost:7777.
- Si l'on suppose qu'il n'y a pas de perte de paquets mais uniquement que l'ordre des paquets n'est pas nécessairement préservé. Est-ce que le protocole
permet de réaliser la somme correctement ?
Vous pouvez tester ce cas de figure en lançant le proxy avec:
$ java -jar UDPProxy.jar 5555 localhost 7777 -long -l 0
Exercice 2 - Meilleure longue Somme de Long
Pour prendre en compte la perte des paquets et le changement d'ordre, on adopte un protocole un peu plus évolué.
Le client veut faire la somme de n longs que si numérotés de 0 à n-1.
Il envoie chaque opérande dans un paquet de la forme [INT|INT|LONG]
(toujours en big endian). Le premier INT est le nombre total d'opérandes (i.e. n). Le second INT est la position de l'opérande (entre 0 et n-1). Le troisième LONG est la valeur de l'opérande.
Pour signaler qu'un paquet a été recu, le serveur renvoie au client un paquet ACK contenant un seul INT (en BigEndian) qui correspond à la position de l'opérande recue.
Le serveur attend les opérandes dans l'ordre. Il attend de recevoir d'abord l'opérande à la position 0, puis l'opérande à la position 1, etc ... S'il a recu toutes les opérandes jusqu'à l'opérande de position 3 et qu'il reçoit l'opérande 5, il ignore le paquet. S'il reçoit à nouveau l'opérande 2, il renvoie un ACK pour l'opérande 2.
Une fois que toutes les opérandes ont été reçues, le serveur renvoie en plus du paquet ACK, un paquet content un LONG (en big endian) correspondant à la somme de toutes les opérandes.
Un client veut par exemple faire la somme de 5 et 7.
Il enverra tout d'abord le paquet [2|0|5]. Quand le serveur recoit, le paquet il renverra le paquet [0] (4 octets). A la reception de cee paquet le client envoie le paquet [2|1|7]. Le serveur renvoie deux paquets: [1] (4 octets) et la somme [12] (8 octets). Si le client ne reçoit pas la réponse du serveur, il renvoie son paquet.
Récupérez le serveur
ServerLongSum.jar
qui implémente ce protocole et lancez le
$ java -jar ServerLongSum.jar 7777
Ecrivez un client ClientLongSum pour ce protocole et vérifiez qu'il fonctionne même quand vous passez par UDPProxy.
Exercice 3 - Encore Meilleure Longue Somme de Long
Dans une version encore plus évoluée du protocole, le serveur n'est pas obligé de recevoir les paquets dans l'ordre. Récupérez le serveur
ServerLongSumSmart.jar
qui implémente ce protocole et lancez le
$ java -jar ServerLongSumSmart.jar 7777
Réalisé un client
ClientLongSumSmart plus évolué qui a deux threads. Un thread envoie les paquets et l'autre qui reçoit les accusés de réceptions. Le thread qui reçoit mémorise les numéros des paquets reçus par le serveur dans un
BitSet qui sera partagé avec le thread qui envoie. Le thread qui envoie utilise une
DelayQueue pour gérer les paquets. Une
DelayQueue est un structure permettant de mettre des objets en donnant un délai avant qu'ils ne soit autorisés à être repris dans la queue. Allez lire la javadoc sur cette classe, vous verrez que les objets que l'on met dans la
DelayQueue doivent implémenter l'interface
Delayed. La classse
DelayedData.java vous donne un point de départ.
Le principe du thread qui fait les envois est le suivant: il remplit la queue
avec tous les paquets. Ensuite il prend un paquet de la queue (
take)
puis il vérifie si l'accusé de réception a été reçu. Si c'est le cas, il n'a rien faire et il recommence à prendre des paquets dans la queue. Si l'accusé de réception n'a pas été reçu, il envoie le paquet correspondant et il rajoute le paquet avec un délai égale au temps d'attente souhaité.
© Université de Marne-la-Vallée