Sunteți pe pagina 1din 11

Forums Tutoriels Magazine FAQs Blogs Projets Chat Newsletter tudes Emploi Club Contacts

Accueil Conception Java .NET Dv. Web EDI Langages SGBD Office Solutions d'entreprise Applications Systmes
Java
FORUMS JAVA FAQs JAVA

Spring

Dv. Web Java

Android

Eclipse

NetBeans
BLOG DISCUSSIONS

TUTORIELS JAVA

JAVASEARCH

SOURCES TV

LIVRES

OUTILS, EDI & API

Architecture Client/Serveur en java avec les sockets


Date de publication : 16/08/2006 Par Romain Guy (Gfx) (home) Vous avez srement dj utilis Internet ou un simple rseau local. Dans un tel environnement, les applications communiquent entre elles par le biais d'objets appels Sockets. Nous allons donc apprendre manipuler ces Sockets... 1. Introduction 2. Le client 2.A. Introduction 2.B. Les Sockets 2.C. Le protocole SMTP 2.D. Autres usages 2.E. Screenshots 3. Le serveur 3.A. Introduction 3.B. Le Socket serveur 3.C. Dfinition du serveur 3.D. Implmentation de ServerSocket 3.E. Une rponse pour la 259.162.11.20, une ! 3.F. Screenshots 4. Les sources

1. Introduction
Dans ce tutoriel, vous allez apprendre tout ce qu'il faut savoir pour dbuter en programmation rseau. Vous allez apprendre ce que sont les sockets et comment les manipuler, vous allez dcouvrir la cration d'un client et celle d'un serveur.

2. Le client
2.A. Introduction
Dans cette partie, nous allons maintenant traiter de la conception et la cration d'un client en rseau avec les sockets. On va apprendre ce que sont les sockets, leur utilit et comment les utiliser, on va aussi apprendre envoyer un mail avec lesdits sockets.

2.B. Les Sockets


Concrtement, qu'est-ce qu'un Socket ? Un Socket est une sorte de point d'ancrage pour les protocoles de transmission de donnes comme TCP/IP. Les Socket sont des objets permettant la gestion de deux flux de donnes: un flux d'entre (InputStream), garantissant la rception des donnes, et un flux de sortie (OutputStream), servant envoyer les donnes. En Java, nous distinguerons deux types de Socket: les Socket simples (dits "clients") et les Socket serveurs. Dans cette partie, nous nous pencherons uniquement sur les Socket clients en crivant un logiciel simple permettant d'envoyer des emails. Un Socket client est tout simplement un Socket qui va se connecter sur un Socket serveur pour lui demander d'effectuer des tches. 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 intresse:
Socket(String host, int port)

Comme vous le voyez, le constructeur du Socket attend deux arguments: une chane de caractres et un entier. Le premier argument dfinit l'adresse IP du serveur sur lequel nous dsirons 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 deuxime argument permet de dfinir le port sur lequel nous allons nous connecter. En effet, une mme machine est tout fait susceptible d'hberger plusieurs serveurs logiciels. Un serveur Web type proposera ainsi un serveur Telnet, un serveur de mail et un serveur Web (voire un serveur FTP). Or, tous ces serveurs utilisent la mme adresse IP. Il nous faut donc les distinguer, et c'est l que le numro de port intervient. Celui-ci est un nombre positif pouvant prendre n'importe quelle valeur. Cependant, quelques numros sont "rservs": 25 pour le protocole SMTP (envoi

pouvant prendre n'importe quelle valeur. Cependant, quelques numros sont "rservs": 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 spcifierons donc le port 25 par dfaut.

2.C. 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 numro de port, de l'e-mail de l'expditeur et de l'e-mail du destinataire. La gestion du protocole SMTP ncessitera l'emploi des deux flux d'entre et de sortie du Socket client. Commenons tout d'abord 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; }

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 mthode sendMail() retourne la valeur vraie. Sinon, la valeur fausse est retourne. Nous ferons grand usage de ceci par la suite, lors de la lecture des rponses du serveur. Maintenant, nous avons besoin de rcuprer les flux permettant l'change d'informations. Les donnes tant sous forme de texte, nous allons encapsuler les flux dans les objets BufferedReader et OutputStreamWriter du package java.io qui nous faciliteront la tche. 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;

Ds 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 donnes. Nous sommes connects, flux prts servir, il ne nous reste plus qu' suivre le protocole SMTP pas pas:
[lecture] [envoyer: [envoyer: [envoyer: [envoyer: [envoyer: [envoyer: [envoyer: [envoyer:

HELO nom de la machine de l'expditeur] MAIL FROM:<expditeur>] RCPT TO:<destinataire>] DATA] en tte] corps du mail] .] QUIT]

A noter qu'aprs chaque envoi, nous faisons galement une lecture. En effet, chaque tape effectue provoque l'envoi d'une rponse 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("Expditeur inconnu");

Ce bout de code correspond l'tape d'identification auprs du serveur. Ici command et response sont deux objets String utiliss tout au long de l'envoi. La premire ligne cre 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 mthodes trace() permettent d'afficher notre dialogue avec le serveur. Notez que lors du second appel de trace() nous lisons une ligne depuis le flux d'entre. Ensuite, cette ligne est vrifie. A ce stade, si la rponse du serveur ne commence pas par "250", le serveur a rejet l'expditeur. Par exemple, si vous avez utilis une adresse e-mail ne portant pas le mme nom de domaine que le serveur (ne marche que sur smtp.free.fr). Pour suivre en dtail chaque tape, reportez vous au code source du logiciel "Login Mailer" disponible la fin de cet article. Celui-ci est suffisamment document pour que vous puissiez saisir aisment le fonctionnement de la mthode sendMail(). Il convient tout de mme de faire attention la dernire 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 remdier cela en envoyant un point d'exclamation la place. Ici encore, reportez vous au code source de l'application LoginMail.

2.D. Autres usages


Ainsi, en utilisant les flux d'entre et de sortie, il est possible, et ce trs facilement, de faire communiquer deux logiciels. L'utilisation d'un Socket client se retrouve dans normment d'applications comme ICQ, IRC, les browsers Web ou mme les jeux !! De la sorte, rien ne vous empche de crer votre propre client pour un autre serveur... cela ne vous demandera que de connatre 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 rception de chanes de caractres (on aurait pu arguer en faveur de l'objet PrintWriter plutt que OutputStreamWriter, mais la mthode println() de PrintWriter envoie le caractre de fin de ligne "\n" alors que SMTP attend "\r\n"). Or, certains serveurs, notamment les serveurs de jeux, sont

extrmement exigeants en termes de vitesse de rception et d'envoi. Dans ce genre de cas, il ne faut surtout pas utiliser des Strings mais plutt 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 rcuprerez ainsi:
InputStream in = socket.getInputStream(); OutputStream out = socket.getOutputStream();

L'utilisation conjointe des mthodes read() (qui renvoie un entier) et write(byte) couvriront alors tous vos besoins.

2.E. Screenshots

L'adressage par IP et numro de port

Telnet...

...mails...

...chat...

...tlchargement, les Sockets sont partout !

3. Le serveur
3.A. Introduction
Chose promise, chose due. Les arcanes des sockets clients n'ayant plus de secrets pour nous, il ne nous reste plus qu' apprendre comment programmer nous mmes ces fameux serveurs sur lesquels nous connections nos logiciels clients. Avant d'aborder l'aspect technique du sujet, intressons nous tout d'abord au fonctionnement gnral d'un serveur logiciel. Nous savons que les clients contiennent des routines ouvrant une connexion sur le port d'un serveur pour y demander et rcuprer des informations. Un serveur logiciel aura donc pour but d'ouvrir un port sur la machine hte et de grer tous les clients se connectant ce port. Cette gestion peut varier d'un type de serveur un autre: simple rponse (un serveur HTTP), distribution aux autres clients (par exemple pour un jeu), mise en relation directe des clients (ICQ ou IRC en mode DCC), et ainsi de suite...

3.B. Le Socket serveur


A l'instar des Socket que nous nommerons "simples", c'est dire les sockets clients, les sockets serveurs proposent un flux d'entre et un flux de sortie. Pour employer un socket serveur en Java, il suffit d'utiliser une instance de la classe ServerSocket du package java.net. La classe ServerSocket offre trois constructeurs parmi lesquels un seul nous intresse:
ServerSocket(int port)

Comme vous pouvez le constater, le constructeur du ServerSocket n'attend qu'un seul et unique argument: un entier. Cet entier joue un peu le mme rle que pour les sockets simples. Il permet de spcifier un port. Mais dans ce cas, cet entier dfinira le numro d'identification du port crer. Vous tes par ailleurs entirement libre du choix du numro du port ds lors que celui-ci est compris dans les limites permises par le type int (de 0 2 147 483 647, c'est dire 2 ^ 32 / 2 - 1 car nous ne pouvons utiliser que des entiers). Toutes les applications rseaux utilisant des ports spcifiques, il vous faudra faire attention ne pas utiliser de numro dj pris. Si votre serveur est destin tre utilis sur une machine personnelle, il est peu probable que l'utilisation des ports 25 (envoi de mails) ou 8080 (HTTP) soit gnante. Cependant, ceci est vivement dconseill, surtout tant donn que la plage de valeurs alloue est largement suffisante pour que vous puissiez y trouver votre bonheur. Dans notre exemple, nous utiliserons le port numro 1705. Afin d'illustrer cet article, nous allons concevoir un logiciel permettant de rpondre des questionnaires simples via un rseau. Ces questionnaires seront une succession de questions choix multiples pour lesquelles chaque bonne rponse donnera un point. Le logiciel se nomme LoginQuiz et se trouve dans les sources disponibles la fin de l'article. La particularit de LoginQuiz est d'utiliser le format XML pour la dfinition de ses questionnaires. Une grande partie du code est ainsi propre la cration des questionnaires depuis des fichiers XML. Nous n'aborderons pas cet aspect de LoginQuiz mais sachez que les fichiers Answer.java, Question.java, QuestionSetHandler.java et QuestionSetReader.java sont ddis cette tche. Toute la partie rseau de notre application est facilite, comme nous allons le voir, par l'utilisation d'une API nomme Caffeine.

3.C. Dfinition du serveur


Implmenter un serveur demande, outre du code, un minimum de rflexion quant la manire dont le serveur transmet et reoit les informations. Notre application ne ncessitant pas d'envois rapides et rpts ( l'inverse de Quake 3 par exemple) de donnes, nous nous contenterons d'un systme fort simple dont voici la description:
Rception: ? : le client demande l'envoi de la question suivante $answer : le client propose la rponse answer et en demande la vrification Envoi: % : code terminal, le questionnaire est fini $0 : mauvaise rponse $1 : bonne rponse ?libell#ID1$rponse1#ID2$rponse2... : libell est la question elle mme, IDx reprsente l'identifiant de la rponse (transmis pour vrification) et rponseX est le libell de la rponse

Hormis l'encodage de la question, notre "protocole" est vraiment trs simple. L'intrt de sparer chaque rponse par le caractre # permettra au client de les sparer trs facilement en utilisant l'objet java.util.StringTokenizer. Penchons nous maintenant sur le coeur du serveur qui est inscrit dans le fichier QuestionSetServer.java. La cration du serveur passe par le constructeur CaffeineServer(int port, String nom, String motDePasse, int nombreConnexionsMax) de la classe parente. Ici, nous utilisons donc le port 1705, n'utilisons pas de mot de passe et dfinissons 25 comme tant le nombre maximum de clients. La seule autre particularit de cette classe est la mthode serverEvent(ServerEvent evt) appel chaque rception de donnes. Nous allons maintenant laisser un instant cette classe pour regarder de plus prs la fameuse CaffeineServer.

3.D. Implmentation de ServerSocket


Les deux parties de la classe CaffeineServer que nous allons tudier sont les mthodes startServer() et getClient(). La premire mthode prend en charge la cration du serveur mme:
try { server = new ServerSocket(serverPort); server.setSoTimeout(1000); } catch (IOException ioe) { System.err.println("[Cannot initialize Server]\n" + ioe); System.exit(1); }

L'instanciation d'un socket serveur est trs simple et demande une seule ligne de code. La deuxime ligne permet de dfinir un dlai au bout duquel une tentative de lecture des sockets connects est considre comme un chec. Cela pour viter de bloquer le serveur en cas de problmes de transmission. Vous constaterez galement que lors de la cration d'un serveur, une exception peut tre rencontre, auquel cas nous arrtons tout. La suite de la mthode startServer() n'offre que peu d'intrt si ce n'est de montrer de quelle manire est-il possible de connatre l'adresse IP de la machine. La seconde mthode, getClient() est place dans la boucle d'un thread et attend tout simplement que quelqu'un daigne bien tenter de se connecter au serveur:
client = server.accept(); new Authorizer(client, password);

Ces deux lignes font tout le travail. L'appel server.accept() va effectivement attendre qu'un client se connecte. Si tel est le cas, nous rcuprons alors un objet Socket. Ensuite, nous crons un nouvel objet Authorizer. Cet objet un peu spcial est une classe interne de CaffeineServer. Cette classe va dmarrer un thread qui se chargera d'administrer la demande de connexion. L'usage d'un thread permet d'viter au serveur de bloquer les demandes des autres clients en attendant la rsolution de la demande en cours. Comme nous n'utilisons pas de mot de passe, la seule partie d'Authorizer qui nous est utile est la suivante:
addClient(new CaffeineSocket(CaffeineServer.this, client));

Ce code va simplement crer un nouvel objet CaffeineSocket et l'ajouter notre liste de clients. CaffeineSocket est un objet grant entirement les Socket clients. En effet, cette classe va crer, de la mme manire que nous l'avions fait pour notre expditeur de mails, des flux d'E/S pour faciliter la communication avec le client. Cet objet cre aussi un thread dans lequel nous nous contentons d'attendre des donnes avant de les transmettre au serveur:
if ((request = reader.readLine()) != null) parent.fireEvent(request, this);

Nous n'irons pas plus avant dans les explications concernant la lecture de donnes puisque c'est exactement la mme mthode que celle utilise pour les sockets clients. Sachez seulement que l'appel fireEvent() est celui qui permettra la classe QuestionSetServer de recevoir les donnes par le biais de la mthode serverEvent().

3.E. Une rponse pour la 259.162.11.20, une !


Revenons maintenant la classe QuestionSetServer. Celle-ci, grce au systme d'vnements mis en place par l'API Caffeine, n'a pas se soucier de la lecture des donnes en provenance des clients, mais seulement de leur envoi. Chaque expdition de donnes est ralise ainsi:
client.getOut().println("donnes"); client.getOut().flush();

L'objet client dsigne un objet CaffeineSocket, la mthode getOut() renvoie un flux PrintWriter que nous utilisons exactement comme pour l'envoi de mail en faisant appel println(). La mthode flush() permet de s'assurer que tous les caractres du message ont ts effectivement envoys. L'exemple propos ici, LoginQuiz, tant un petit peu complexe, une tude attentive du code source, comment, vous permettra de saisir toutes les, rares, subtilits et notamment d'approfondir votre exprience des sockets clients.

3.F. Screenshots

Deux clients rpondant au questionnaire

Un questionnaire crit en XML

Test de notre protocole sous Telnet

Un autre exemple de serveur

4. Les sources
- Le logiciel LoginMail - Le logiciel LoginQuiz

Articles et tutoriels Java L'essentiel de Java en une heure L'API java.nio du JDK 1.4 Inversion de contrle en Java L'introspection Le Java Community Process Conception de tests unitaires avec JUnit Les Strings se dchanent Prsentation de SWT La programmation rseau en Java avec les sockets Du bon usage de l'hritage et de la composition Les rfrences et la gestion de la mmoire en Java Constructeurs et mthodes exportes en Java Les membres statiques, finaux et non immuables en Java Les classes et objets immuables en Java Comprendre et optimiser le Garbage Collector Les principes de la programmation d'une interface graphique Les oprateurs binaires en Java Prenez le contrle du bureau avec JDIC Les Java Data Objects (JDO version 1.0.1) La persistance des donnes avec Hibernate 2.1.8 Journalisation avec l'API Log4j Java 5.0 et les types paramtrs Les annotations de Java 5 Java 1.5 et les types paramtrs Crer un moteur de recherche avec Lucene Articles et tutoriels Swing Threads et performance avec Swing Rechercher avec style en utilisant Swing Splash Screen avec Swing et Java3D Drag & Drop avec style en utilisant Swing Attendre avec style en utilisant Swing Mixer Java3D et Swing Articles et tutoriels Java Web Redcouvrez le web avec Wicket
C ette c ration es t mis e dis pos ition s ous un c ontrat C reative C ommons (P aternit - P artage des C onditions I nitiales l'I dentique).

Responsables bnvoles de la rubrique Java : mlny84 - Mickael Baron - Contacter par email

Developpez.com
Nous contacter Participez Informations lgales

Services
Forum Java Blogs Hbergement

Partenaires
Hbergement Web

Copyright 2000-2012 - www.developpez.com

S-ar putea să vă placă și