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.


Rappel : vous devez configurer le workspace d'Eclipse (File > Switch WorkSpace) pour qu'il corresponde au répertoire EXAM présent dans le home de votre session de TP noté.

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).

Vous avez le droit de consulter les transparents du cours.

A vos chronomètres!

Toutes les classes demandées dans cet exercice doivent se trouver dans le package fr.uge.net.ex1

Dans cet exercice, on cherche à réaliser un serveur UDP bloquant pour le protocole Chrono décrit ci-dessous :

Protocole Chrono
Dans le protocole Chrono, les clients envoient des paquets contenant un entier LONG en BigEndian représentant la date d'envoi du paquet. La date est fournie par la méthode System.currentTimeMillis(). La réponse du serveur contient :
  • un INT en BigEndian contenant le temps mis par le paquet reçu pour arriver au serveur (on suppose que le client et le serveur sont à la même heure),
  • un INT en BigEndian contenant la moyenne des temps de trajet des 10 derniers paquets reçus en provenance de ce client (si le client a envoyé moins de 10 paquets, c'est la moyenne des temps de tous ses paquets),
  • un INT en BigEndian contenant la moyenne des temps de trajet de tous les paquets reçus par le serveur, quel que soit le client

Par exemple, si le serveur vient de démarrer et qu'il reçoit, à la date 1000, un paquet du Client1 avec la date 900, il renverra un paquet contenant 100|100|100 : Le paquet a mis 1000 - 900 = 100 millisecondes. Pour l'instant un seul paquet a été reçu du Client1 et la moyenne est donc 100 pour les paquets du Client1. La moyenne pour le serveur est de 100 également (tous clients confondus).
Si ensuite il reçoit à la date 1050, un autre paquet du Client2 avec la date 850, il renverra le paquet 200|200|150. Le paquet a mis 1050 - 850 = 200 millisecondes. Pour l'instant un seul paquet a été reçu du Client2 et la moyenne est donc 200 pour les paquets du Client2. Comme le serveur a reçu deux paquets ayant mis respectivement 100 et 200 millisecondes, la moyenne pour le serveur est de 150 (tous clients confondus).

Le deuxième INT renvoyé par le serveur correspond à la moyenne des temps de trajet des 10 derniers paquets reçus de ce client et pas la moyenne de tous les paquets reçus de client. Le troisième INT renvoyé par le serveur correspond à la moyenne de tous les temps trajets de tous les paquets reçus depuis tous les clients.

Dans une classe ServerChrono, écrire un serveur UDP bloquant pour le protocole Chrono.
Vous pouvez utiliser la trame ci-après comme point de départ : ChronoServer.java. Pensez à gérer proprement les exceptions.

Vous pouvez le tester avec le client ClientChrono.jar et le proxy UDPProxy.jar. Le client fourni envoie un paquet toutes les secondes et affiche les réponses du serveur.

$ java -jar UDPProxy.jar 5678 localhost 8765
$ java fr.uge.net.ex1.ServerChrono 8765
$ java -jar ClientChrono.jar localhost 8765
$ java -jar ClientChrono.jar localhost 5678

L'un des clients passe par le proxy mais pas le deuxième. Vous devrez observer un temps très faible pour le client ne passant pas par le proxy et un temps plus élevé pour le client passant par le proxy.

Serveur TCP MultiSet bloquant fixed prestarted

Toutes les classes demandées dans cet exercice doivent se trouver dans le package fr.uge.net.ex2

Dans cet exercice, vous devez implémenter un serveur TCP multi-thread en mode bloquant, suivant l'architecture fixed prestarted vue en cours, qui implémente le protocole MultiSet présenté ci-dessous. Dans ce protocole, le client envoie des chaînes de caractères au serveur et le serveur va répondre en disant combien de fois cette chaîne a été proposée par ce client, par tous les clients connectés en ce moment au serveur et par tous les clients depuis le démarrage du serveur.

Protocole MultiSet

Les trames du client sont des chaînes de caractères encodées en UTF-8 et terminées par un octet valant 0. En comptant cet octet, la requête d'un client ne peut pas dépasser 1024 octets.

Le serveur répond avec 3 INT en BigEndian qui vont correspondre respectivement au :

  • nombre de fois que ce client a proposé cette chaîne de caractères,
  • nombre de fois qu'un client connecté actuellement au serveur à proposé cette chaîne
  • nombre de fois que cette chaîne a été proposée par un client depuis le démarrage du serveur.

Par exemple le serveur vient de démarrer et un client A veut envoyer la chaîne "Maurice". Il enverra les octets suivants :

4D 61 75 72 69 63 65 00
qui s'interprètent comme suit :
4D 61 75 72 69 63 65 // les octets de "Maurice" encodés en UTF8
00// un octet valant 0 marquant la fin de la chaîne

Le serveur répondra par une trame contenant 3 fois un INT valant 1 encodé en BigEndian.

00 00 00 01 00 00 00 01 00 00 00 01
qui s'interprète comme suit:
00 00 00 01 // nb de fois où "Maurice" a été envoyée par le client A
00 00 00 01 // nb de fois où "Maurice" a été envoyée par un client connecté
00 00 00 01 // nb de fois où "Maurice" a été envoyée par un client 

Si le client A renvoie la chaîne "Maurice", le serveur répondra avec la trame 2|2|2. Si un client B se connecte et envoie lui aussi la chaîne "Maurice", le serveur lui répondra 1|3|3 car le client B n'a envoyé cette chaîne qu'une fois, les clients A et B qui sont les seuls clients connectés ont envoyé cette chaîne 3 fois au total et enfin, le serveur, depuis son démarrage, a reçu la chaîne "Maurice" 3 fois. Si le client A se déconnecte et que le client B renvoie la chaîne "Maurice", le serveur lui répondra avec 2|2|4.

À partir du squelette de la classe ServerFixedPrestartedMultiSet.java, écrivez un serveur en mode bloquant suivant l'architecture fixed prestarted vue en cours, pour ce protocole. Le serveur prend comme paramètre le nombre maximum de clients qui peuvent se connecter simultanément.

Pour tester votre serveur, vous pouvez utiliser le client ClientMultiSet.jar. Ce client lit au clavier des chaînes de caractères et les envoie au serveur. Il affiche les entiers reçus du serveur.
Par exemple, vous pouvez lancer votre serveur, qui accepte 3 clients en simultané, sur le port 7777 :

$java fr.uge.net.ex2.ServerFixedPrestartedMultiSet 7777 3

Vous pouvez le tester depuis ou au plus 3 terminaux simultanément en lançant un client avec:

$java -jar ClientMultiSet.jar localhost 7777

Serveur TCP MultiSet non-bloquant

Toutes les classes demandées dans cet exercice doivent se trouver dans le package fr.uge.net.ex3

Dans cet exercice, vous devez écrire un serveur TCP en mode non-bloquant, qui implémente le protocole MultiSet vu à l'exercice précédent.

À partir du squelette de la classe ServerNonBlockingMultiSet.java, écrivez un serveur en mode non-bloquant pour ce protocole. On demande que votre serveur puisse (quand c'est possible) être en OP_READ|OP_WRITE. Attention, le squelette fourni est un serveur pour le protocole Echo, qui suit l'architecture vue en cours. Il est nécessaire de l'adapter et de le faire évoluer : c'est simplement un point de départ.
Tous vos buffers doivent faire au moins 1024 octets.

Pour tester votre serveur, vous pouvez utiliser le client ClientMultiSet.jar. Ce client lit au clavier une chaîne de caractères, l'envoie au serveur et affiche la réponse du serveur.
Par exemple, vous pouvez lancer votre serveur sur le port 7777 :

$java fr.uge.net.ex3.ServerNonBlockingMultiSet 7777 
$java -jar ClientMultiSet.jar localhost 7777