L'examen est composé de trois exercices indépendants qui peuvent être traités dans l'ordre que vous voulez. Les exercices 2 et 3 utilisent le même protocole. Il faut donc lire la présentation du protocole au début de l'exercice 2 pour pouvoir faire l'exercice 3.
Rappel : si ce n'est pas déjà le cas, 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érifiez 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.
La Java doc est ici.
Dans cet exercice, vous devez écrire un client TCP en mode bloquant pour le protocole PokemonObserver décrit ci-dessous. Ce protocole permet à un client de recevoir des notifications sur les Pokémons observés dans la nature avec leur différentes caractéristiques.
Le client peut s'enregistrer pour recevoir des notifications pour les Pokémons observés dans une zone géographique donnée. Il envoie une trame contenant le nom de la zone géographique au format suivant: un INT en BigEndian qui donne le nombre d'octets de la chaîne encodée en UTF-8, puis la chaîne encodée en UTF-8.
Dès qu'un Pokémon est observé dans une zone géographique pour laquelle le client est enregistré, le serveur enverra toutes les informations sur le Pokémon observé au format suivant:
Le taille des chaînes de caractères une fois encodées en UTF-8 ne peut pas dépasser 1020 octets.
Par exemple, si le client veut les informations sur les Pokémons observés dans la zone géographique "Paris", il enverra la trame suivante :
00 00 00 05 50 61 72 69 73qui se décomposent comme suit :
00 00 00 05 \\ un INT en BigEndian valant 5 50 61 72 69 73 \\ les octets de la chaîne "Paris" en UTF-8
Si le serveur détecte un Pokémon "Ronflex" dans la zone géographique "Paris" avec les caractéristiques suivantes :
Il enverra la trame suivante :
// Pokémon name "Ronflex" (7 bytes) 00 00 00 07 // INT: length of "Ronflex" in UTF-8 (7 bytes) 52 6F 6E 66 6C 65 78 // "Ronflex" in UTF-8 // Zone name "Paris" (5 bytes) 00 00 00 05 // INT: length of "Paris" in UTF-8 (5 bytes) 50 61 72 69 73 // "Paris" in UTF-8 00 03 // SHORT: number of characteristics (3) // Characteristic 1: "size" 00 00 00 04 // INT: length of "size" in UTF-8 (4 bytes) 73 69 7A 65 // "size" in UTF-8 00 00 00 00 00 00 01 2C // LONG: value 300 // Characteristic 2: "weight" 00 00 00 06 // INT: length of "weight" in UTF-8 (6 bytes) 77 65 69 67 68 74 // "weight" in UTF-8 00 00 00 00 00 00 00 64 // LONG: value 100 // Characteristic 3: "swag" 00 00 00 04 // INT: length of "swag" in UTF-8 (4 bytes) 73 77 61 67 // "swag" in UTF-8 00 00 00 00 00 00 23 28 // LONG: value 9000
On veut écrire un client qui lit au clavier des noms de zones géographiques et qui envoie la trame correspondante au serveur. Et parallèle, le client affiche toutes les informations sur les Pokémons observés reçues du serveur. Le squelette de la classe est donné et il contient déjà les deux threads nécessaires. Il vous faut implémenter :
performRequest(String region)
qui va écrire sur la socketChannel
la trame correspondant à la chaîne region. Cette méthode ne ferme pas la socketChannel
et renvoie true
si la trame a été envoyée correctement et false
sinon.listen()
qui est exécutée dans un thread et qui affiche en boucle les informations sur les Pokémons observés reçues du serveur.En partant du squelette
ClientPokemonObserver.java
, implémentez le client bloquant demandé.
Vous pouvez tester votre client avec le serveur ServerPokemonObserver.jar. Pour vérifier la réponse, vous pouvez regarder l'affichage du serveur.
$java -jar ServerPokemonObserver.jar 7777
Votre client prendra en paramètre l'adresse et le port du serveur comme ci-après (en gras, ce que l'utilisateur saisit sur l'entrée standard).
$java fr.uge.net.tcp.exam2025.ex1.ClientPokemonObserver localhost 7777 What region are you interested in ? Paris What region are you interested in ? ============== Pokemon : Bulbasaur Location : Paris energy -> 92 agility -> 20 specialDefense -> 64 accuracy -> 46 luck -> 49 attack -> 37 ============== ============== Pokemon : Kangaskhan Location : Paris speed -> 65 accuracy -> 14 ==============
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 PokeSpot présenté ci-dessous.
Dans le protocole PokeSpot, peuvent envoyer le nom de Pokémon qu'ils ont observés dans la nature et demander pour un Pokémon donné combien de fois il a été observé.
Pour dire qu'il a observé un Pokémon, le client envoie une trame contenant le nom du Pokémon observé au format suivant :
L'octet valant 33 correspond au caractère '!' en UTF-8. On supposera donc que le nom du Pokémon ne contient pas de '!'.
Quand le serveur reçoit une trame d'observation, il n'envoie aucune trame en réponse.
Pour demander des informations sur un Pokémon, le client envoie une trame contenant le nom du Pokémon observé au format suivant :
Par exemple, si un client veut signaler qu'il a vu Ronflex, il enverra la trame suivante :
00 00 00 01 52 6F 6E 66 6C 65 78 33 ... 33
qui se décompose comme suit :
00 00 00 01 // INT: 1 52 6F 6E 66 6C 65 78 33 ... 33 // "Ronflex" en UTF-8 suivi de 250 octets valant 33
Si un client veut demander des informations sur Ronflex, il enverra la trame suivante :
00 00 00 02 52 6F 6E 66 6C 65 78 33 ... 33
Supposons qu'aucun client n'est connecté au serveur et qu'un client A se connecte au serveur et envoie un trame disant qu'il a observé Ronflex. Si le client A envoie une demande d'information sur Ronflex, le serveur renverra [1,1,1]. Si le client A envoie une autre demande d'information sur Pikachu, le serveur renverra [0,0,0].
Si un client B se connecte et envoie une demande d'information sur Ronflex, le serveur renverra [0,1,1]. Si il envoie une trame d'observation sur Ronflex et qu'il fait une demande d'information sur Ronflex, le serveur renverra [1,2,2].
Si le client A se déconnecte puis que le client B envoie une trame d'observation sur Ronflex, le serveur renverra [1,1,2].
À partir du squelette de la classe
ServerFixedPrestartedPokeStop.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 ClientPokeSpot.jar
. Ce client envoie un trame à chaque fois que vous appuyez sur la touche entrée. Si la ligne commence par un OBSERVE, il envoie une trame d'observation. Si la ligne commence par un ASK, il envoie une trame de demande d'information. Il affiche les valeurs reçues par le serveur.
Par exemple, vous pouvez lancer votre serveur, qui accepte 3 clients en simultané, sur le port 7777 :
$java fr.uge.net.tcp.exam2025.ex2.ServerFixedPrestartedPokeSpot 7777 3
Vous pouvez le tester depuis au plus 3 terminaux simultanément en lançant un client avec :
$java -jar ClientPokeSpot.jar localhost 7777 Type your command OBSERVE Pokémon or INFO Pokémon. QUIT to stop INFO R Information for R Spotted by this client 0 many times Spotted by a connected client 0 many times Spotted by since start of server 0 many times OBSERVE R INFO R Information for R Spotted by this client 1 many times Spotted by a connected client 1 many times Spotted by since start of server 1 many times QUIT Closing client
Dans cet exercice, vous devez écrire un serveur TCP en mode non-bloquant, qui implémente le protocole PokeSpot décrit à l'exercice précédent.
À partir du squelette de la classe
ServerNonBlockingPokeSpot.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 1024 octets.
Pour tester votre serveur, vous pouvez utiliser le client ClientPokeSpot.jar
.
Par exemple, vous pouvez lancer votre serveur sur le port 7777 :
$java fr.uge.net.tcp.exam2025.ex3.ServerNonBlockingPokeSpot 7777
$java -jar ClientPokeSpot.jar localhost 7777