:: Enseignements :: Master :: M1 :: 2015-2016 :: Programmation d'applications réseaux ::
![[LOGO]](http://igm.univ-mlv.fr/ens/resources/mlv.png) | Fiabilisation d'une succession d'échanges UDP |
Exercice 1 - Paquets identifiés envoyés et acquittés un par un
On souhaite disposer d'un programme qui utilise les services
d'un serveur de mise en majuscule pour réaliser les opérations suivantes:
- lire un fichier texte ligne par ligne
- stocker toutes ces lignes dans une liste,
- envoyer ces lignes au serveur et stocker toutes les réponses dans une autre liste
- écrire ces lignes mises en majuscule dans un fichier.
Cependant, on a constaté pour cela qu'il faut que le client ait un moyen d'identifier,
lorsqu'il reçoit une réponse, à quelle requête elle correspond.
Pour cela, nous améliorons notre protocole "BetterUpperCase" en "IdBetterUpperCase":
nous allons préfixer les données envoyées au serveur par une nouvelle information:
un entier de type long, stocké en Big Endian, qui identifie de manière unique
la requête et sa réponse: si une requête doit être ré-envoyée parce qu'elle n'a
pas reçu de réponse, le même identifiant est utilisé. Chaque requête (émanant
d'une nouvelle chaîne à mettre en majuscule) doit avoir un identifiant différent.
Ainsi, pour chaque chaîne de caractère à envoyer au serveur pour mise en majuscule,
la représentation utilisée sera la suivante:
-
Un long en BigEndian identifiant la requête (chaque requête a
un identifiant unique, qui est également utilisé dans la représentation
de la réponse à cette requête)
-
Un int en BigEndian correspondant à la longueur du nom de l'encodage
écrit en ASCII;
-
Le nom de l'encodage en ASCII;
-
Les octets de la chaîne encodée avec cet encodage.
Nous vous fournissons un nouveau serveur
ServerIdBetterUpperCase.jar
qui implémente ce protocole en utilisant l'identifiant, et vous pouvez réutiliser le proxy
UDP
UDPProxy.jar qui introduit des délais ou
des pertes dans les échanges de paquets UDP.
$ java -jar ServerIdBetterUpperCaseUDP.jar 4545
$ java -jar UDPProxy.jar 7777 localhost 4545 -no-swap
Les classes suivantes doivent vous permettre de construire une application cliente
qui permettra d'interroger ce serveur en passant par le proxy afin de vérifier que
l'ensemble des chaînes récupérées correspond bien à l'ensemble des chaînes envoyées.
- La classe
ClientIdBetterUpperCaseUDP.java
qui correspond au client qui lit les lignes du fichier pour les envoyer au serveur.
- Pour envoyer au serveur, ce client utilise un objet de la classe
Requester: cette classe abstraite permet au client
d'interroger le serveur en utilisant le protocole, et propose des méthodes génériques pour construire un paquet,
décoder unee chaîne dans un paquet, envoyer au serveur, etc... La méthode d'envoi de la liste de
chaînes au serveur est abstraite, et son implémentation est laissée à la classe suivante.
- La classe OneByOneRequester
hérite de Requester et implémente cette méthode en réalisatn l'envoi une par une
des chaînes.
Vous devez compléter ce qui manque de ces classes et tester par:
$ java fr.upem.net.udp.ClientIdBetterUpperCaseUDP utf-8 fichier.txt localhost 7777
Après avoir vérifié que le comportement attendu est obtenu, et que votre protocole
est fiable, essayer d'évaluer le temps de réponse total pour un fichier de N lignes,
avec une probabilité p de perte de paquet (via le proxy). Mesurez expérimentalement
le temps pris par votre application et comparez.
Exercice 2 - Paquets identifiés envoyés en rafale et acquités de manière asynchrone
Le temps d'attente systématique (synchrone) de la réponse après l'envoi
d'un paquet n'est pas optimal.
Il serait intéressant de pouvoir envoyer tous les paquets, sans se soucier de
leur réponse ou de leur perte, et de recevoir les réponses de manière asynchrone,
l'idée étant que l'on aura à ré-envoyer toutes les requêtes pour lesquelles
aucune réponse n'a été retenue.
Cette solution semble bien plus performante, mais elle nécessite de mettre en
place un mécanisme permettant de savoir, pour l'ensemble des paquets envoyés,
lesquels ont reçu (ou pas) une réponse, et d'assurer que les réponses seront
bien remises dans l'ordre où elles doivent être: dans notre exemple de client
ci-dessus qui met en majuscule toutes les lignes d'un fichier, il faut bien
entendu respecter l'ordre des lignes du fichier...
Pour cela, vous allez écrire une classe
BurstRequester héritant, comme
OneByOneRequester, de la classe abstraite
Requester.
L'implémentation de
toUpperCase() dans
BurstRequester pourra
utilser un
java.util.BitSet du nombre de lignes -- paquets -- à
envoyer pour représenter lesquelles de ces lignes ont reçu une réponse
(au départ aucune). La méthode
toUpperCase() devra cette fois réaliser
les opérations suivantes:
- créer et intitialiser ce BitSet
- créer et démarrer une thread d'envoi des paquets qui envoit un paquet
pour chaque ligne de la liste qui n'a pas encore reçue de réponse (il est plus
facile de faire une thread pour l'envoi, contrairement à l'exercice précédent
où il était plus facile de faire une thread d'écoute). Le processus est répété
toutes les TIMEOUT millisecondes.
- écouter les réponses reçues du serveur, les stocker et mettre à jour
le BitSet
Bien entendu, vous tiendrez compte du fait que le BitSet est accédé par
la thread qui exécute
toUpperCase() en concurrence avec la thread
d'envoi des paquets.
Pour tester votre classe, il suffira de modifier une ligne dans le
main du client
ClientIdBetterUpperCaseUDP:
Requester requester = new BurstRequester(dest);
© Université de Marne-la-Vallée