P
'
t
i
t
e
C
h
a
t
t
e
 
spacer~ NO I WILL NOT FIX YOUR COMPUTER Articles | Connexion
 
~Les sockets clients

Précédent  
  Java  
  Suivant
 Présentation

Après le sujet quelque peu théorique du mois dernier, voici la première partie d'une série de trois articles traitant de la gestion des réseaux en Java. Les deux premiers volets porteront sur les Socket, les outils indispensables pour communiquer entre applications, et le dernier sur le protocole RMI, véritable bijou de programmation objet.
 Sommaire


 Les Sockets

Concrètement, qu'est-ce qu'un Socket ? Un Socket est une sorte de point d'ancrage pour les protocoles de transmission de données comme TCP/IP. Les Socket sont des objets permettant la gestion de deux flux de données: un flux d'entrée (InputStream), garantissant la réception des données, et un flux de sortie (OutputStream), servant à envoyer les données. En Java, nous distinguerons deux types de Socket: les Socket simples (dits "clients") et les Socket serveurs. Dans cet article, nous nous pencherons uniquement sur les Socket clients en écrivant un logiciel simple permettant d'envoyer des e-mails. Un Socket client est tout simplement un Socket qui va se connecter sur un Socket serveur pour lui demander d'effectuer des tâches. Netscape utilise des Sockets clients par exemple... Mais avant de passer à la pratique, analysons la classe Socket du package java.net de Java. Cette classe contient divers constructeurs dont seul un nous intéresse:

Socket(String host, int port)
       
      
JextCopier dans Jext | Jext | Plugin Codegeek
Comme vous le voyez, le constructeur du Socket attend deux arguments: une chaîne de caractères et un entier. Le premier argument définit l'adresse IP du serveur sur lequel nous désirons nous connecter. Cette adresse peut prendre la forme classique X.X.X.X (par exemple 127.0.0.1 pour votre propre machine) ou vous pouvez utiliser un nom (localhost est équivalent à 127.0.0.1). Le deuxième argument permet de définir le port sur lequel nous allons nous connecter. En effet, une même machine est tout à fait susceptible d'héberger plusieurs serveurs logiciels. Un serveur Web type proposera ainsi un serveur Telnet, un serveur de mail et un serveur Web (voir un serveur FTP). Or, tous ces serveurs utilisent la même adresse IP. Il nous faut donc les distinguer, et c'est là que le numéro de port intervient. Celui-ci est un nombre positif pouvant prendre n'importe qu'elle valeur. Cependant, quelques numéros sont "réservés": 25 pour le protocole SMTP (envoi de mails), 23 pour le Telnet, 8080 pour le protocole HTTP (serveur Web)... Notre but étant de pouvoir envoyer des mails, nous spécifierons donc le port 25 par défaut.


 Le protocole SMTP

Envoyer des e-mails est un jeu d'enfant. Nous avons besoin de l'adresse du serveur de mail (par exemple smtp.free.fr), du numéro de port, de l'e-mail de l'expéditeur et de l'e-mail du destinataire. La gestion du protocole SMTP nécessitera l'emploi des deux flux d'entrée et de sortie du Socket client. Commençons tout d'abord par créer par nous connecter au serveur en construisant une nouvelle instance de l'objet Socket.

public boolean sendMail(String host, int port, String sender, String receiver)
{
  Socket smtpPipe;

  try
  {
    smtpPipe = new Socket(host, port);
    if (smtpPipe == null)
      return false;
  } catch (IOException ioe) { return false; }
  return true;
}
       
      
JextCopier dans Jext | Jext | Plugin Codegeek
Par la suite, nous admettrons que tout le code source sera tapé dans le bloc try/catch. Si tout s'est bien passé lors de la connexion, la méthode sendMail() retourne la valeur vraie. Sinon, la valeur fausse est retournée. Nous ferons grand usage de ceci par la suite, lors de la lecture des réponses du serveur. Maintenant, nous avons besoin de récupérer les flux permettant l'échange d'informations. Les données étant sous forme de texte, nous allons encapsuler les flux dans les objets BufferedReader et OutputStreamWriter du package java.io qui nous faciliteront la tâche. Le code à rajouter est:

BufferedReader in = new BufferedReader(
  new InputStreamReader(smtpPipe.getInputStream()));
OutputStreamWriter out = new OutputStreamWriter(smtpPipe.getOutputStream());
if (in == null || out == null)
  return false;
       
      
JextCopier dans Jext
Dès lors, un simple appel de in.readLine() permettra de recevoir une ligne depuis le serveur et out.write(String + "\r\n") permettra d'envoyer des données. Nous sommes connectés, flux prêts à servir, il ne nous reste plus qu'à suivre le protocole SMTP pas à pas:

[lecture]
[envoyer: HELO nom de la machine de l'expéditeur]
[envoyer: MAIL FROM:<expéditeur>]
[envoyer: RCPT TO:<destinataire>]
[envoyer: DATA]
[envoyer: en tête]
[envoyer: corps du mail]
[envoyer: .]
[envoyer: QUIT]
       
      
JextCopier dans Jext
A noter qu'après chaque envoi, nous faisons également une lecture. En effet, chaque étape effectuée provoque l'envoi d'une réponse de la part du serveur indiquant si l'on peut continuer ou non. Voici le code type d'une étape:

command = "MAIL FROM:<" + sender + ">";
out.write(command + "\r\n");
out.flush();
trace(command);
trace(response = in.readLine());
if (!response.startsWith("250"))
  return error("Expéditeur inconnu");
       
      
JextCopier dans Jext
Ce bout de code correspond à l'étape d'identification auprès du serveur. Ici command et response sont deux objets String utilisés tout au long de l'envoi. La première ligne crée le message à envoyer au serveur. Les deux suivantes servent à effectuer l'envoi (flush() permettant de "vider" le flux pour s'assurer que tout a été envoyé). Ensuite les méthodes trace() permettent d'afficher notre dialogue avec le serveur. Notez que lors de du second appel de trace() nous lisons une ligne depuis le flux d'entrée. Ensuite, cette ligne est vérifiée. A ce stade, si la réponse du serveur ne commence pas par "250", le serveur a rejeté l'expéditeur. Par exemple, si vous avez utilisé une adresse e-mail ne portant pas le même nom de domaine que le serveur (guy.romain@free.fr ne marche que sur smtp.free.fr). Pour suivre en détail chaque étape, reportez vous au code source du logiciel "Login Mailer" sur le CD. Celui-ci est suffisamment documenté pour que vous puissiez saisir aisément le fonctionnement de la méthode sendMail(). Il convient tout de même de faire attention à la dernière étape de l'envoi de mail. Vous noterez que l'on envoie un simple point (".") pour signifier que l'on a terminé. Mais que se passera-t il si le corps du mail contient une ligne avec pour seul texte, un point ? La connexion sera close par le serveur. Le protocole SMTP offre cependant un moyen de remédier à cela en envoyant un point d'exclamation à la place. Ici encore, reportez vous au code source de l'application LoginMail.


 Autres usages

Ainsi, en utilisant les flux d'entrée et de sortie, il est possible, et ce très facilement, de faire communiquer deux logiciels. L'utilisation d'un Socket client se retrouve dans énormément d'applications comme ICQ, IRC, les browsers Web ou même les jeux !! De la sorte, rien ne vous empêche de créer votre propre client pour un autre serveur... cela ne vous demandera que de connaître le "protocole" du serveur convoité. Faites attention cependant aux flux que vous utilisez. Ici, nous avons encapsulé nos flux dans des objets rendant plus pratique l'envoi et la réception de chaînes de caractères (on aurait pu arguer en faveur de l'objet PrintWriter plutôt que OutputStreamWriter, mais la méthode println() de PrintWriter envoie le caractère de fin de ligne "\n" alors que SMTP attend "\r\n"). Or, certains serveurs, notamment les serveurs de jeux, sont extrêmement exigeant en terme de vitesse de réception et d'envoi. Dans ce genre de cas, il ne faut surtout pas utiliser des Strings mais plutôt des entiers (type int) voir des primitifs de type byte. Si vous vous retrouvez dans cette situation, conservez tout simplement les flux de base du Socket que vous récupérerez ainsi:

InputStream in = socket.getInputStream();
OutputStream out = socket.getOutputStream();
       
      
JextCopier dans Jext | Jext | Plugin Codegeek
L'utilisation conjointe des méthodes read() (qui renvoie un entier) et write(byte) couvriront alors tous vos besoins. Si vous êtes désireux d'aller un peu plus loin et d'étudier quelques exemples de Socket clients, vous trouverez sur le CD les sources d'une application de téléchargement, celles d'un logiciel de chat destiné à deux utilisateurs et enfin celles d'une API nommée Caffeine dont le but avouée est de vous aider à implémenter un support réseau dans votre logiciel.



par Romain Guy
romain.guy@jext.org
http://www.jext.org
Dernière mise à jour : 14/10/2006


Précédent  
  Java  
  Suivant

 
#ProgX©2005 Mathieu GINOD - Romain GUY - Erik LOUISE