mercredi 15 juillet 2009

Socket & ServerSocket

Dans mon apprentissage du Java, j'ai décidé de faire un détour pour apprendre comment me connecter sur un serveur (en donnant une adresse d'hôte et un port). Ça m'a également mené à lire à propos du "contraire", à savoir comment recevoir des connexions sur un certain port.

C'est assez cool parce que ça permet de créer des clients pour des protocoles existants, mais aussi de créer ses propres protocoles.

J'ai écrit un mini-programme qui fonctionne très mal et qui permet de se connecter sur un serveur IRC (http://www.undernet.org/). En gros, tous les messages reçus du serveur sont imprimés dans la console ou le terminal, et on doit également taper nos commandes dans ce terminal (en d'autres mots, il n'y a pas vraiment de distinction entre "message reçu" et "message envoyé"). Aussi, le protocole IRC nécessite plein d'information lors de la connexion et dans un ordre précis, ce qui est généralement géré automatiquement par le client. Comme mon fameux client est archaïque, il faut tout faire à la main, et disons-le, c'est chiant (j'ai cherché *partout* pour trouver comment faire... j'ai finalement réussi, mais ô combien de temps perdu).

Aussi, le programme a un problème assez grave en ce moment qui est qu'il ne ferme aucune connexion lorsqu'il quitte. En fait, la manière que ça fonctionne c'est qu'il faut ouvrir deux flux (un de lecture et l'autre d'écriture), ainsi qu'un socket en soit (une connexion au serveur, bref). Le programme, pour le moment, ne ferme aucun des flux ni le socket (je pense d'ailleurs que ça pourrait expliquer mes problèmes persistants de connexion après trop de tentatives, mais je ne m'y connais pas assez).


L'intérêt là-dedans, au-delà de la possibilité d'écrire un client en utilisant un protocole quelconque géré par un serveur, est que l'on peut créer un protocole soi-même, écrire le programme pour recevoir les connexions et gérer les commandes reçues, et bâtir le client qui doit être remis à l'utilisateur pour se connecter au serveur. Il y a donc moyen de produire entièrement quelque chose fonctionnant par Internet (ou Intranet ou whatever), pour peu qu'on ait un serveur qui l'héberge.

À titre d'exemple: je pourrais créer un serveur d'échecs mettons. Le programme sur le serveur (qui écouterait pour les connexions) interprèterait (selon le protocole que j'aurais moi-même rédigé) les commandes envoyées par les utilisateurs. Les utilisateurs, eux, pourraient utiliser une interface que j'aurais également créée moi-même, laquelle permettrait de communiquer le serveur en envoyant des messages interprétables par le serveur (i.e. selon le même protocole).


Absolument merveilleux, non?

Bon évidemment, j'en parle comme si c'était facile et faisable et qu'un singe pourrait faire pareil, mais c'est quand même pas simple. Je veux dire, il faut quand même coder tout ça (coder la manière que le protocole est géré, bref). Tout ça n'est clairement pas simple et demanderait beaucoup de travail. Mais de toute manière, le but de l'exercice n'était pas de réécrire le monde de la programmation... c'était juste pour voir comment se connecter à un serveur en Java...

2 commentaires:

Nicolas a dit...

Ouais je me rappelle de ça les connexions qui meurent pas, faudrait que je retrouve comment j'avais résolu ce problème là :s

...à moins que t'aies trouvé ?

Seigneur a dit...

ben c'était pour ça le Thread qqch = new Thread(this) en fait.

Je pense que j'ai vraiment mal pensé le problème pour tout te dire. Je me suis fait trois classes: une qui se connecte et qui démarre les 2 threads d'écoute, une classe qui sert de thread pour recevoir ce qui vient du serveur, et une autre pour envoyer les trucs au serveur.

l'affaire c'est que au lieu de faire extends Thread, j'ai simplement fait implements Runnable et j'ai mis les public void run(). Bon, le problème c'est qu'un thread peut être interrompu, et on se sert habituellement de la méthode isInterrupted() pour contrôler si le thread devrait fonctionner (dans le void run()).

Fek on aurait genre:

public void run() {
while (!leThread.isInterrupted()) { ... }
}

Mais on peut pas utiliser ça dans la méthode run pcq cest pas un extends thread... fek ce que je pensais faire, cest Thread nom = new Thread(this), puis dans la méthode run mettre while (!nom.isInterrupted()) { ... }.

En tout cas, j'ai pas encore essayé... pour l'instant, ce qui se passe, c'est que je garde la référence des threads dans la classe où ya la main, pi quand le thread denvoi au serveur termine, il a une variable qui devient true, et j'ai un autre thread qui sert à écouter seulement cette variable-là, et qui ensuite utilise la référence des deux threads pour faire .interrupt(). Après ça par contre ça fucke parce que les threads essaient de continuer, ça me donne une erreur IOException, et j'ai mis un System.exit(1); dans le gestionnaire d'erreurs... entk, lol...

tu vois, c'est vraiment compliqué pour rien mon affaire.