UDP non-bloquant

Serveur : Echo non-bloquant

Le but de cet exercice est de mettre en application les concepts vus dans le cours sur UDP en mode non-bloquant. On cherche à réaliser un serveur pour le protocole Echo.

Protocole Echo
Dans le protocole Echo, le serveur renvoie aux clients les paquets qu'il reçoit à l'identique. On supposera que les paquets ne dépassent pas 1024 octets.

En partant du fichier ServerEcho.java, écrivez un tel serveur ServerEcho qui prend en argument son port d'écoute.

Attention rappelez-vous que même si le sélecteur renvoie une clé de sélection en disant qu'une réception ou qu'un envoi de paquet est possible, il n'y a aucune garantie que la réception ou l'envoi soit effectivement réalisé lors de l'appel à datagramChannel.receive() ou datagramChannel.send().

  • Vous pouvez tester si un paquet a bien été reçu en vérifiant l'adresse renvoyée par datagramChannel.receive() : elle est null si aucun paquet n'a été reçu.
  • Vous pouvez tester si un paquet a bien été envoyé en testant le buffer.hasRemaining() après le datagramChannel.send(buffer, sender) : si l'envoi n'a pas eu lieu, la zone de travail de buffer est inchangée.

Si l'envoi ou la réception n'ont pas eu lieu, il faut que votre code interroge à nouveau le sélecteur et attende qu'il repropose la clé pour tenter une nouvelle fois.

Il est très rare que le sélecteur propose une clé sans que l'envoi ou la réception ne soit possible. Vous ne pourrez donc pas tester votre code dans ces cas et il vous faudra le prévoir par vous-même en regardant précisément le comportement de votre code en cas d'échec de l'envoi ou de la réception.

Pour tester votre serveur, vous pouvez utiliser le client NetcatUDP.jar. Ce client envoie des paquets correspondants à chaque ligne tapée au clavier (encodée en UTF8) et affiche la chaîne correspondant au paquet reçu (décodée en UTF8).

$ java fr.uge.net.udp.nonblocking.ServerEcho 4545
$ java -jar NetcatUDP.jar localhost 4545 UTF8
toto
String: toto

Nous allons maintenant légèrement modifier le protocole Echo pour obtenir le protocole EchoPlus.

Protocole EchoPlus
Dans ce protocole, le serveur ne renvoie plus les paquets reçus à l'identique mais renvoie le paquet dans lequel chaque octet a été incrémenté de 1 modulo 256.

On supposera que les paquets ne dépassent pas 1024 octets.

Par exemple, en recevant le paquet de 7 octets suivant :

    +----------------------+
    | FF 0A 11 1F FF 00 01 |
    +----------------------+
le serveur renverra au client le paquet :
    +----------------------+
    | 00 0B 12 20 00 01 02 |
    +----------------------+

Écrivez une classe serveur ServerEchoPlus qui implémente en mode non-bloquant un serveur pour le protocole EchoPlus.
Vous pourrez partir du code de votre classe ServerEcho.

Vérifiez bien que votre code est correct dans le cas où datagramChannel.send() ou datagramChannel.receive() n'effectuent pas l'envoi ou la réception malgré le fait qu'ils aient pu être sélectionné.

Pour tester votre serveur, vous pouvez utiliser le client NetcatUDP.jar.

$ java fr.uge.net.udp.nonblocking.ServerEchoPlus 4545
$ java -jar NetcatUDP.jar localhost 4545 UTF8
toto
Received 4 bytes from /127.0.0.1:4545
String: upup

Serveur Echo multi-port NIO

Dans cet exercice, nous cherchons à écrire un serveur Echo ServerEchoMultiPort qui prend en argument une plage de ports. Si vous lancez votre serveur avec:

java fr.uge.udp.nonblocking.ServerEchoMultiPort 7000 7100
votre serveur se comportera comme un serveur Echo sur chacun des ports de la plage [7000 .. 7100] (inclus).

Jusqu'à présent, le sélecteur ne surveillait qu'un seul DatagramChannel. Dans cet exercice, il faudra créer un DatagramChannel pour chaque port de la plage et tous les enregistrer auprès du sélecteur.

Il faudra stocker pour chaque SelectionKey un ByteBuffer et une InetSocketAddress. Pour stocker ces deux informations vous créerez une classe interne Context.

Pour associer à chaque SelectionKey un objet Context, on pourrait utiliser une Map<SelectionKey,Context>. Cependant la classe SelectionKey permet déjà d'attacher un objet quelconque à la clé. La méthode selectionKey.attach(Object obj) permet de stocker un objet dans la clé et la méthode selectionKey.attach() permet récupérer cet objet.

Remarquez que l'on peut attacher un objet à la création de la clé (c'est-à-dire au moment de l'enregistrement de la DatagramChannel auprès du sélecteur):

    dc.register(selector, SelectionKey.OP_READ, new Context());

Vous pouvez tester votre serveur en lancant le client ClientTestEchoMultiPort.jar comme suit:

java -jar ClientTestEchoMultiPort.jar localhost 7000 7100
Ce test simule 10 clients qui envoient 100 paquets sur la plage de ports entre 7000 et 7100. Il vérifie que tous les paquets réponses sont bien reçus. Si tout se passe bien, vous devez voir:
No error found.