TCP non bloquant

Client en mode non-bloquant

Dans cet exercice, on réalise un client pour le protocole Chaton en mode non-bloquant.

Protocole Chaton

Les trames circulant entre les clients et le serveur représentent des messages. Un message contient un login et un texte au format suivant :

+------------------+------------+------------------+------------+
| Login size (INT) | Login UTF8 | Texte size (INT) | Texte UTF8 |
+------------------+------------+------------------+------------+

Les entiers sont en Big Endian. Les chaînes ne font pas plus de 1024 octets.

Quand un message est reçu par le serveur, il le transmet à tous les clients.

Nous vous proposons de partir du squelette suivant ClientChat.java. Dans ce squelette, la lecture au clavier se fait dans le thread console et la boucle de sélection est exécutée par le thread main. Attention, cela signifie qu'il faut utiliser une mécanisme thread-safe pour les faire communiquer.

Dans le squelette, on considère que cette communication est gérée dans les méthodes sendCommand(String msg) et processCommands() que vous devrez implémenter.
  • Une solution est d'utiliser une BlockingQueue, mais attention, on n'est pas dans le cas d'un producteur-consommateur au sens strict.
  • Une solution (probablement plus simple) est de synchroniser ces échanges.
  • Mais la solution la plus propre serait de faire une classe thread-safe pour cette partie là.

Écrivez un client non-bloquant pour le protocole Chaton.

Console

On souhaite maintenant rajouter une console au serveur non-bloquant : c'est à dire la possibilité de lire des instructions au clavier.

Votre console devra reconnaître trois instructions :

Rajouter une console à votre ServerEcho dans une une classe ServerEchoWithConsole.

Comme nous l'avons vu dans le cours, les clés du sélecteur ne peuvent pas être modifiées par un autre thread que celui qui exécute la boucle de sélection. Il faudra donc, comme pour le client de l'exercice précédent, faire particulièrement attention à la communication entre le thread qui lit au clavier avec le thread du sélecteur.

Vous pouvez tester votre serveur en utilisant ClientEchoSlow.jar et/ou la commande netcat. Attention, lorsque la communication est coupée avec le jar, le message "Sender thread killed by IOException ..." apparaît mais son exécution continue, c'est normal.

(Optionnel) Console et suppression des clients inactifs

On veut maintenant déconnecter les clients inactifs dans un serveur non-bloquant.

Rajouter à votre ServerEchoWithConsole la suppression des clients inactifs dans une classe ServerEchoWithConsoleAndTimeout

Il n'est pas nécessaire de rajouter de nouveaux threads ! Une solution peu coûteuse consiste à rajouter un champ booléen activeSinceLastTimeoutCheck dans chaque Context. Ce booléen est à vrai initialement et il sera remis à vrai à chaque appel à doRead et doWrite. Dans la boucle de sélection, on va, toutes les TIMEOUT millisecondes, parcourir les contextes de tous les clients connectés et fermer ceux dont le booléen est faux. Pour tous les clients encore connectés on positionnera le booléen à faux.
De cette manière, si pendant les TIMEOUT millisecondes qui séparent deux parcours, un client n'a pas fait d'appel à doRead ou doWrite, il sera déconnecté.
Encore une fois, il faut prendre garde au fait que la méthode select est bloquante. Pour garantir que l'on ne passe pas plus de TIMEOUT millisecondes à attendre dans le select, on utilisera la version avec timeout de la méthode select.

  selector.select(this::treatKey,TIMEOUT);