Examen 2h sur machine

Consignes

L'examen est composé de trois exercices indépendants qui peuvent être traités dans l'ordre que vous voulez.

Le premier exercice sera noté sur environ 9 points, le deuxième exercice 6 points et le troisième sur 5 points. Ce barème est fourni à titre indicatif et est susceptible d'évoluer. Il vous est donné pour vous permettre de répartir votre temps.


Rappel : vous devez créer un projet Java dont les sources seront stockées dans répertoire EXAM présent dans le home de votre session de TP noté (assurez-vous que c'est bien le cas du workspace d'Eclipse par défaut).

Vérifier bien que tous vos fichiers sont dans le répertoire EXAM. Tout ce qui n'est pas dans ce répertoire est perdu quand vous vous déconnectez (ou en cas de panne).

La Java doc est ici.

Client UDP bloquant ClassRoom

Toutes les classes de cet exercice doivent se trouver dans le package fr.uge.net.udp.exam2324.ex1.

Le but de l'exercice est de réaliser un client UDP bloquant pour protocole ClassRoom décrit ci-dessous.

Le protocole ClassRoom

Le protocole ClassRoom permet de récupérer auprès d'un serveur les noms et les prénoms de tous les étudiants d'une classe. Le client envoie un paquet contenant le nom de la classe et le serveur va renvoyer autant de paquets qu'il y a d'étudiants dans la classe. Pour demander les étudiants d'une classe, le client envoie un paquet contenant :
  • un INT en BigEndian qui donne le nombre d'octets du nom de la classe encodé en UTF8,
  • suivi des octets du nom de la classe encodé en UTF8.
Par exemple, pour demander les étudiants de la classe Master1, le client enverra le paquet :
  00 00 00 07 4D 61 73 74 65 72 31
Les paquets envoyés par le client ne peuvent pas dépasser 1024 octets. Le serveur va renvoyer autant de paquets qu'il y a d'étudiants dans la classe. S'il y a n étudiants dans la classe, les étudiants sont numérotés de 0 à n-1 et le serveur va renvoyer n paquets. Le paquet correspondant à l'étudiant numéro i contiendra :
  • un INT en BigEndian qui donne le numéro i de l'étudiant,
  • un INT en BigEndian qui donne le nombre total n d'étudiants dans la classe,
  • un INT en BigEndian qui donne le nombre d'octets du prénom de l'étudiant encodé en UTF8,
  • suivi des octets du prénom de l'étudiant encodé en UTF8,
  • suivi des octets du nom de l'étudiant encodé en UTF8.

Par exemple si la classe Master1 contient les quatre étudiants suivants :

0. Matthew Turner
1. Samuel Adams
2. Mason Green
3. Avery Campbell
Le serveur va envoyer 4 paquets. Attention, ce protocole est un peu différent des protocoles vus en cours car un paquet envoyé par le client provoque l'émission de plusieurs paquets par le serveur. Le paquet correspondant à l'étudiant numéro 2 Mason Green sera le suivant :
  00 00 00 02 00 00 00 04 00 00 00 05 4D 61 73 6F 6E 47 72 65 65 6E
qui se décompose comme suit :
00 00 00 02          => numéro de l'étudiant
00 00 00 04          => nombre total d'étudiants
00 00 00 05          => taille de "Mason" encodé en UTF8
4D 61 73 6F 6E       => "Mason" encodé en UTF8
47 72 65 65 6E       => "Green" encodé en UTF8

Les paquets envoyés par le serveur ne peuvent pas dépasser 2048 octets. On supposera que tous les paquets contiennent la même valeur pour le nombre total d'étudiants.

Dans un premier temps, on va supposer qu'aucun paquet ne peut être perdu ou retardé et vous implémenterez un client qui fonctionne dans ce cas là pour le protocole ClassRoom. Ce client prendra sur la ligne de commande le nom de la classe et affichera la liste des étudiants dans l'ordre fourni par le serveur. Si le paquet correspondant au nom de la classe dépasse la taille maximum du protocole ClassRoom, le client affichera une erreur et terminera.

Plus précisément, le client prendra en paramètres sur la ligne de commande les informations suivantes :

Dans une classe ClientClassRoom, écrire un client UDP bloquant comme décrit ci-dessus.
Vous pouvez utiliser la trame suivante comme point de départ : ClientClassRoom.java. Elle contient un record Student(String firstName, String lastName) et sa méthode launch doit renvoyer la liste des Student de la classe dans l'ordre donné par le serveur.

Vous testerez votre client en utilisant le serveur fourni ServerClassRoom.jar qui se démarre en fournissant le numéro de port d'écoute :

% java -jar ServerClassRoom.jar 7777

Si vous lancez votre client avec cette liste :

% java fr.uge.net.udp.exam2324.ex1.ClientClassRoom localhost 7777 Master1

vous devriez obtenir l'affichage suivant :

0. Matthew Turner
1. Samuel Adams
2. Mason Green
3. Avery Campbell

ClientClassRoom tolérant aux pertes de paquets

On veut maintenant prendre en compte le fait que des paquets UDP peuvent être perdus entre le client et le serveur, dans un sens comme dans l'autre. On rappelle que le serveur répond avec tous les étudiants de la classe, dans des paquets séparés. Au cas où au moins un paquet est perdu, votre client doit reposer sa question au bout de TIMEOUT millisecondes exactement. Le TIMEOUT sera une constante de votre client qui vaudra 300.

Recopiez votre classe ClientClassRoom dans une nouvelle classe ClientClassRoomFull que vous allez faire évoluer pour tenir compte des pertes de paquets.

Récupérez le jar UDPProxy.jar et démarrez-le entre votre client et le serveur. Dans trois fenêtres de terminal différentes, exécutez :

% java -jar ServerClassRoom.jar 4545 
$ java -jar UDPProxy.jar 7777 localhost 4545 -no-swap
$ java fr.uge.net.udp.exam2324.ex1.ClientClassRoomFull localhost 7777 Master1 

et vérifiez que l'affichage produit est correct. N'hésitez pas à tester avec des classes un peu plus grosses (par exemple, Master2 contient 9 étudiants)

Serveur bloquant Stats UDP

Toutes les classes de cet exercice doivent se trouver dans le package fr.uge.net.udp.exam2324.ex2.

Dans cet exercice, on cherche à réaliser un serveur bloquant pour le protocole Stats décrit ci-après. Le protocole fournit un service extrêmement rudimentaire de statistiques en UDP.

Protocole Stats

Dans le protocole Stats, les clients envoient des paquets qui contiennent un int positif en BigEndian et le serveur répond avec un paquet contenant 2 ints et 2 longs en BigEndian. Plus précisément, les réponses du serveur sont de la forme suivante :

  +-----------------------------------------------------------+
  | min (INT) | max (INT) | average (LONG) | different (LONG) |
  +-----------------------------------------------------------+
  

avec :

  • min est le plus petit entier reçu de ce client depuis le démarrage du serveur,
  • max est le plus grand entier reçu de ce client depuis le démarrage du serveur,
  • average est la moyenne (arrondie à l'entier inférieur) de tous les entiers reçus de ce client depuis le démarrage du serveur,
  • different est le nombre d'entiers différents reçus de tous les clients depuis le démarrage du serveur.

Par exemple, si on démarre un serveur et qu'il reçoit de Bob l'INT 5, le serveur répondra avec [5 (INT) | 5 (INT) | 5 (LONG) | 1 (LONG)] car 5 est le plus petit entier reçu de Bob, 5 est aussi le plus grand entier reçu de Bob, la moyenne des entiers reçus de Bob est 5 et que le serveur n'a reçu qu'un seul nombre.

Si Bob envoie l'INT 4, le serveur répondra [4 (INT) | 5 (INT) | 4 (LONG) | 2 (LONG)] car 4 est le plus petit entier reçu de Bob, 5 est le plus grand entier reçu de Bob, la moyenne des entiers reçus de Bob est (4+5)/2=4 et que le serveur a reçu deux nombres distincts au total 4 et 5.

Si Bob envoie l'INT 1, le serveur répondra [1 (INT) | 5 (INT) | 3 (LONG) | 3 (LONG)] car 1 est le plus petit entier reçu de Bob, 5 est le plus grand entier reçu de Bob, la moyenne des entiers reçus de Bob est (1+4+5)/3=3 et que le serveur a reçu trois nombres distincts au total 1, 4 et 5.

Si Bob envoie à nouveau l'INT 1, le serveur répondra [1 (INT) | 5 (INT) | 2 (LONG) | 3 (LONG)] car 1 est le plus petit entier reçu de Bob, 5 est le plus grand reçu entier de Bob, la moyenne des entiers reçus de Bob est (1+1+4+5)/4=2 et que le serveur a reçu trois nombres distincts au total 1, 4 et 5.

Si un nouveau client Charlie envoie l'INT 4, le serveur répondra [4 (INT) | 4 (INT) | 4 (LONG) | 3 (LONG)] car 4 est le plus petit entier reçu de Charlie, 4 est le plus grand entier reçu de Bob, la moyenne des entiers reçus de Bob est (1+1+4+5)/4=2 et que le serveur a reçu trois nombres distincts au total 1, 4 et 5.

Dans une classe ServerStats, écrire un serveur UDP bloquant pour le protocole Stats.
Vous pouvez utiliser la trame ci-après comme point de départ : ServerStats.java.

Si vous lancez votre serveur comme ci-dessous :

% java fr.uge.net.udp.exam2324.ex2.ServerStats 7777

Vous pouvez le tester avec le client ClientStats.jar. Ce client prend en paramètre l'adresse du serveur.

% java -jar ClientStats.jar localhost 7777 
Please enter your positive number:
5
févr. 14, 2024 9:50:22 PM fr.uge.net.udp.exam2324.ex2.ClientStats listener
INFO: Received 24 bytes from /127.0.0.1:7777
Received the answer [min= 5; max= 5; average= 5; different= 1 ] from /127.0.0.1:7777
Please enter your positive number:
4
févr. 14, 2024 9:50:33 PM fr.uge.net.udp.exam2324.ex2.ClientStats listener
INFO: Received 24 bytes from /127.0.0.1:7777
Received the answer [min= 4; max= 5; average= 4; different= 2 ] from /127.0.0.1:7777
Please enter your positive number:
3
févr. 14, 2024 9:50:39 PM fr.uge.net.udp.exam2324.ex2.ClientStats listener
INFO: Received 24 bytes from /127.0.0.1:7777
Received the answer [min= 3; max= 5; average= 4; different= 3 ] from /127.0.0.1:7777

Serveur Range non-bloquant

Toutes les classes de cet exercice doivent se trouver dans le package fr.uge.net.udp.exam2324.ex3.

Dans cet exercice, vous devez écrire un serveur UDP en mode non-bloquant qui implémente le protocole très simple décrit ci-après.

Protocole Range

Le client envoie un paquet qui contient 2 int en BigEndian avec le premier int inférieur ou égal au second int. Quand le serveur reçoit un de ces paquets contenant les int n1 et n2, il renvoie un paquet contenant l'int n1 en BigEndian, puis un paquet contenant l'int n1+1 en BigEndiant, et ainsi de suite jusqu'au paquet contenant l'int n2.

Si le serveur reçoit le paquet :

    +-------------------------+
    | 00 00 00 05 00 00 00 08 |
    +-------------------------+
qui contient les int 5 et 8 ...

... alors le serveur renverra au client les quatre paquets suivants :

    +-------------+
    | 00 00 00 05 |
    +-------------+

    +-------------+
    | 00 00 00 06 |
    +-------------+

    +-------------+
    | 00 00 00 07 |
    +-------------+

    +-------------+
    | 00 00 00 08 |
    +-------------+
qui correspondent aux int 5, 6, 7 et 8 respectivement.

À partir du squelette de la classe ServerRange.java, écrivez un serveur en mode non-bloquant pour ce protocole.

Pour tester votre serveur, vous pouvez utiliser le client ClientRange.jar. Ce client prend en arguments l'adresse et le port du serveur. Il demande d'entrer au clavier les deux int à envoyer au serveur séparés par un point virgule. Il affiche les réponses reçues par le serveur.

Par exemple, si votre serveur est lancé sur le port 7777 :

$java fr.uge.net.udp.exam2324.ex3.ServerRange 7777 

Vous pouvez le tester depuis un autre terminal (en gras, ce que l'utilisateur saisit sur l'entrée standard) :

$java -jar ClientRange.jar localhost 7777
Your input must be in the format int1;int2 with int1<=int2:
5;8
Sending the packet for [5, 8]
févr. 14, 2024 7:05:55 PM fr.uge.net.udp.exam2324.ex3.ClientRange listener
INFO: Received 4 bytes from /127.0.0.1:7777
Received packet [5]
févr. 14, 2024 7:05:55 PM fr.uge.net.udp.exam2324.ex3.ClientRange listener
INFO: Received 4 bytes from /127.0.0.1:7777
Received packet [6]
févr. 14, 2024 7:05:55 PM fr.uge.net.udp.exam2324.ex3.ClientRange listener
INFO: Received 4 bytes from /127.0.0.1:7777
Received packet [7]
févr. 14, 2024 7:05:55 PM fr.uge.net.udp.exam2324.ex3.ClientRange listener
INFO: Received 4 bytes from /127.0.0.1:7777
Received packet [8]
Your input must be in the format int1;int2 with int1<=int2:
...