Professional Documents
Culture Documents
On ne
va pas tout apprendre sur les sockets mais tudier le plus important concernant ces classes du
rpertoire java.net.
Avant de vous lancer dans la lecture de ce tutoriel, les deux premires parties de cysboy sur le
langage Java ainsi que la lecture de celui sur les threads et les flux d'entres et sorties (1/2)
sont primordiales pour bien suivre le cours !
Je vous recommande galement de lire le chapitre de Dalshim Bien fermer ses threads en
Java si vous voulez bien matriser la fermeture de vos threads.
Les sockets servent communiquer entre deux htes appels Client / Serveur l'aide d'une
adresse IP et d'un port que j'appelle prise ; ces sockets permettront de grer des flux entrant et
sortant afin d'assurer une communication entre les deux (le client et le serveur), soit de
manire fiable l'aide du protocole TCP/IP, soit non fiable mais plus rapide avec le protocole
UDP. Nous allons tudier le premier mode, le mode TCP/IP
Voici ce qu'on peut raliser l'aide des sockets :
Les sockets sont utiliss dans plusieurs autres langages, tels que :
Lire les parties histoire et dfinitions de tutoriels ci-dessus ne vous fera pas de mal.
Ne tardons pas et commenons.
getHostName() : elle retourne le nom de la machine dont l'adresse est stocke dans
l'objet.
getAddress() : elle retourne l'adresse IP stocke dans l'objet sous forme d'un tableau de
4 octets.
toString() : elle retourne un String qui correspond au nom de la machine et son
adresse.
Et le rsultat est :
L'adresse locale est : softdeath/239.254.78.177
L'adresse du serveur du site du zro est : www.siteduzero.com/80.248.219.12
3
Fastoche, hein ?
La classe InetAdress peut lever une exception de type UnknownHostException, tchez de ne
pas l'oublier !
Nous savons maintenant comment rcuprer l'adresse IP de notre machine ou d'une machine
distante, que diriez-vous si l'on l'utilisait pour crer notre tout premier socket ? C'est parti
En outre, java.net comprend la classe ServerSocket, qui met en oeuvre une sorte de prise que
les serveurs peuvent utiliser pour couter et accepter les connexions des clients. Ce qui nous
donne :
ServerSocket socketserver = new ServerSocket(numero_port);
Ainsi on obtient un objet de la classe ServerSocket sur un port spcifique : si ce dernier est
0, le socket est cre sur n'importe quel port libre.
Il existe deux autres constructeurs ; l'un a deux paramtres, le premier est bien sr le numro
de port et le nombre total de connexion simultanes acceptes, voyez :
ServerSocket socketserver = new ServerSocket(numer_port,nbr_max);
nbr_max est le nombre maximal de connexions traites simultanment. Par exemple au-del
de cinq tentatives de connexion conscutives autorises, les connexions sont refuss.
Pour le second constructeur il suffit de spcifier l'adresse locale du serveur.
ServerSocket socketserver = new ServerSocket(numer_port,nbr_max,adresse_loc
ale);
Quant au client, celui-ci connat le nom de la machine sur laquelle le serveur est en excution
et le numro de port sur lequel il coute. Le client va demander une connexion au serveur en
s'identifiant avec son adresse IP ainsi que le numro de port qui lui est li.
Pour cela, le package java.net fournit une classe Socket qui met en uvre une connexion
bidirectionnelle entre votre programme Java et un autre programme situ sur le rseau. La
classe Socket permet de cacher les dtails d'implmentation de cette connexion. En utilisant
cette classe en lieu et place d'un code natif, vos programmes peuvent communiquer sur le
rseau quel que soit la plateforme sur laquelle ils se trouvent. La cration d'un socket pour un
programme client s'effectue l'aide d'un des constructeurs suivants :
Socket socket = new Socket(param1, param2)
Le premier paramtre correspond l'identit du client, il peut tre une chaine de caractre ou
de type InetAddress, param2 correspond au numro de port sur lequel on souhaite se
connecter sur le serveur. Il est possible galement de spcifier son adresse local comme
troisime paramtre et le numro de port local :
Socket socket = new Socket(adresse_distante, port_distant, adresse_locale,
port_locale)
Une fois le socket cr, l'attente de connexion provenant du client se fait l'aide de la
mthode accept().
La mthode accept() reste bloquante tant qu'elle n'a pas dtect de connexion.
Afin d'viter une attente infinie, il est possible de spcifier un dlai maximal d'attente l'aide
d'un mutateur setSoTimeout.
Si un timeout est une valeur strictement positive, l'appel accept() va gnrer une attente
maximale gale timeout. Si ce temps expire, une exception de type InterruptedIOException
est leve sans toute fois que la socket de type ServerSocket ne soit invalide. La lecture de ce
timeout se fait l'aide de l'accesseur getSoTimeout().
Ct client, si la connexion est accepte, une socket est cr et le client peut utiliser la socket
pour communiquer avec le serveur.
L'tablissement d'une connexion peut lever une exception de type IOException.
On va essayer d'tablir une communication. Vous avez tout les lments porte de main,
vous pouvez dsormais tablir une connexion, au boulot !
...Ce n'tait pas si difficile que a, voyons la correction
Le client et le serveur peuvent prsent communiquer par l'criture ou la lecture de leurs
prises.
Serveur.java
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
public class Serveur {
public static void main(String[] zero) {
ServerSocket socketserver
Socket socketduserveur ;
try {
Client.java
import
import
import
import
public
java.io.IOException;
java.net.InetAddress;
java.net.Socket;
java.net.UnknownHostException;
class Client {
. Maintenant,
Attention : il ne faut jamais oublier de fermer le socket ! Sinon si vous utilisez le mme port
dans un autre programme, ce (l'action de fermer une socket) ne sera plus possible car il (le
port) sera occup !
change de message
Une fois la connexion tablie et les sockets en possession, il est possible de rcuprer le flux
d'entre et de sortie de la connexion TCP vers le serveur. Il existe deux mthodes pour
permettre la rcupration des flux :
getInputStream() de la classe InputStream. Elle nous permet de grer les flux entrant ;
getOutputStream() de la classe OuputStream. Elle nous permet de grer les flux
sortant.
Ces deux mthodes nous permettent donc de grer les flux en entre et en sortie. En gnral le
type d'entre et sortie utilis est BufferedReader et InputStreamReader pour la lecture,
PrintWriter pour l'criture. Mais on peut utiliser tous les autres flux.
En se basant sur l'annexe du tuto Java :
BufferedReader : cette classe permet de lire des caractres partir d'un flux tamponn,
afin de faire des lectures plus rapides ;
InputStreamReader : convertit un flux binaire en flux de caractres : elle convertit un
objet de type InputStream en objet de type Reader ;
PrintWriter : la classe PrintWriter ajoute un flux la possibilit de faire des critures
sous forme de texte des types primitifs Java, et des chanes de caractres.
Serveur.java
import
import
import
import
java.io.BufferedReader;
java.io.IOException;
java.io.InputStreamReader;
java.io.PrintWriter;
import
import
import
import
import
public
java.net.InetAddress;
java.net.ServerSocket;
java.net.Socket;
java.net.UnknownHostException;
java.io.PrintWriter;
class Serveur {
try {
socketserver = new ServerSocket(2009);
System.out.println("Le serveur est l'coute du port "+sockets
erver.getLocalPort());
socketduserveur = socketserver.accept();
System.out.println("Un zro s'est connect");
out = new PrintWriter(socketduserveur.getOutputStream());
out.println("Vous tes connect zro !");
out.flush();
socketduserveur.close();
socketserver.close();
}catch (IOException e) {
e.printStackTrace();
}
}
}
Client.java
import
import
import
import
import
import
import
public
java.io.BufferedReader;
java.io.IOException;
java.io.InputStreamReader;
java.io.PrintWriter;
java.net.InetAddress;
java.net.Socket;
java.net.UnknownHostException;
class Client {
socket.close();
}catch (UnknownHostException e) {
e.printStackTrace();
}catch (IOException e) {
e.printStackTrace();
}
}
}
Ct Serveur
Aprs tablissement de la connexion, le serveur obtient son socket qu'il utilise pour grer le
flux sortant l'aide de socketduserveur.getOutputStream() ; ensuite, l'aide de la mthode
println on envoie un message au client, on utilise flush pour vider le buffer tout simplement.
Et pour finir on ferme la connexion.
Ct Client
Aprs avoir obtenu notre socket, on utilise socket.getInputStream() pour rcuprer le flux
sortant. La mthode readLine() nous permet de lire une chane de caractres. Il existe
plusieurs autres mthodes telles :
Je pars du principe que vous connaissez ce que sont les threads et comment les utiliser et
pourquoi doit-on les utiliser dans nos programme, on va donc attaquer directement la pratique.
Le principe d'utilisation des Threads est simple (sera simple si vous suivez attentivement
).
Aprs avoir crer un objet ServerSocket par le serveur, on le place (l'objet) comme paramtre
un constructeur de la classe qui implmente la classe Runnable ou tend la classe Thread,
ds qu'un client souhaite se connecter avec le serveur, un Thread s'occupe de la connexion, il
ne sera plus la peine de faire appel au serveur lorsqu'un client souhaite se connecter, tout le
boulot sera confi un Thread.
Vous commencez comprendre l'utilit des Threads
avec le temps vous ne pourrez plus
vous en passer.
Voyons un petit exemple de connexion Multi-Threads en image et avec un code source
toujours :
Serveur.java
import java.io.IOException;
import java.net.*;
public class Serveur {
public static void main(String[] zero){
ServerSocket socket;
try {
socket = new ServerSocket(2009);
Thread t = new Thread(new Accepter_clients(socket));
t.start();
System.out.println("Mes employeurs sont prts !");
} catch (IOException e) {
e.printStackTrace();
}
}
}
class Accepter_clients implements Runnable {
private ServerSocket socketserver;
Client.java
import java.io.IOException;
import java.net.*;
public class Client {
public static void main(String[] zero){
Socket socket;
try {
socket = new Socket("localhost",2009);
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
Rsulats :
Mes employeurs sont prts !
Le client numero 1 est connect !
Le client numero 2 est connect !
Le client numero 3 est connect !
Si vous m'avez bien suivis vous ne devriez pas avoir du mal comprendre ce code. Ds que
quelqu'un tape la porte, on demande un employer de lui ouvrir la porte, celui-l va le
saluer et lui dire bye bye avec socket.close(); s'il ne veut pas parler (communiquer)
.
message lui dira qu'il est connect, ils pourront ensuite envoyer tous leurs messages au
serveur. Voil : trs simple.
On devra avoir quelque chose de ce genre ct serveur, pour plusieurs clients la fois :
Le serveur est l'coute du port 2009
Un zro veut se connecter
softdeath vient de se connecter
softdeath : salut, M. le serveur, j'ai besoin de vos services.
Un zro veut se connecter
chabanus vient de se connecte
chabanus : salut, j'ai besoin d'accder telles donnes.
Allez au boulot !
try {
while(true){
socket = socketserver.accept();
System.out.println("Un zro veut se connecter
");
Authentification .java
import java.net.*;
import java.util.NoSuchElementException;
import java.util.Scanner;
import java.io.*;
public class Authentification implements Runnable {
private Socket socket;
private PrintWriter out = null;
private BufferedReader in = null;
private String login = "zero", pass = null;
public boolean authentifier = false;
public Thread t2;
public Authentification(Socket s){
socket = s;
}
public void run() {
try {
in = new BufferedReader(new InputStreamReader(socket.getInputSt
ream()));
out = new PrintWriter(socket.getOutputStream());
while(!authentifier){
out.println("Entrez votre login :");
out.flush();
login = in.readLine();
out.println("Entrez votre mot de passe :");
out.flush();
pass = in.readLine();
if(isValid(login, pass)){
out.println("connecte");
System.out.println(login +" vient de se connecter ");
out.flush();
authentifier = true;
}
else {out.println("erreur"); out.flush();}
}
t2 = new Thread(new Chat_ClientServeur(socket,login));
t2.start();
} catch (IOException e) {
System.err.println(login+" ne rpond pas !");
}
}
private static boolean isValid(String login, String pass) {
boolean connexion = false;
try {
Scanner sc = new Scanner(new File("zero.txt"));
while(sc.hasNext()){
if(sc.nextLine().equals(login+" "+pass)){
connexion=true;
break;
}
}
} catch (FileNotFoundException e) {
System.err.println("Le fichier n'existe pas !");
}
return connexion;
}
}
Chat_ClientServeur.java
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
public class Chat_ClientServeur implements Runnable {
private Socket socket = null;
private BufferedReader in = null;
private PrintWriter out = null;
private String login = "zero";
private Thread t3, t4;
public Chat_ClientServeur(Socket s, String log){
socket = s;
login = log;
}
public void run() {
try {
in = new BufferedReader(new InputStreamReader(socket.getInputStream
()));
out = new PrintWriter(socket.getOutputStream());
Thread t3 = new Thread(new Reception(in,login));
t3.start();
Thread t4 = new Thread(new Emission(out));
t4.start();
} catch (IOException e) {
System.err.println(login +"s'est dconnect ");
}
}
}
Emission .java
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Scanner;
public class Emission implements Runnable {
private PrintWriter out;
private String message = null;
private Scanner sc = null;
public Emission(PrintWriter out) {
this.out = out;
}
public void run() {
sc = new Scanner(System.in);
while(true){
System.out.println("Votre message :");
message = sc.nextLine();
out.println(message);
out.flush();
}
}
}
Reception.java
import java.io.BufferedReader;
import java.io.IOException;
public class Reception implements Runnable {
private BufferedReader in;
private String message = null, login = null;
public Reception(BufferedReader in, String login){
this.in = in;
this.login = login;
}
public void run() {
while(true){
try {
message = in.readLine();
System.out.println(login+" : "+message);
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
Serveur.java
import java.io.*;
import java.net.*;
public class Serveur {
public static ServerSocket ss = null;
public static Thread t;
public static void main(String[] args) {
try {
ss = new ServerSocket(2009);
System.out.println("Le serveur est l'coute du port "+ss.getL
ocalPort());
t = new Thread(new Accepter_connexion(ss));
t.start();
} catch (IOException e) {
System.err.println("Le port "+ss.getLocalPort()+" est dj util
is !");
}
}
}
Ct Client
Chat_ClientServeur.java
import java.io.*;
import java.net.*;
import java.util.Scanner;
public class Chat_ClientServeur implements Runnable {
private Socket socket;
private PrintWriter out = null;
private BufferedReader in = null;
private Scanner sc;
private Thread t3, t4;
public Chat_ClientServeur(Socket s){
socket = s;
}
public void run() {
try {
out = new PrintWriter(socket.getOutputStream());
in = new BufferedReader(new InputStreamReader(socket.getInputSt
ream()));
sc = new Scanner(System.in);
} catch (IOException e) {
System.err.println("Le serveur distant s'est dconnect !");
}
}
}
Client.java
import java.io.*;
import java.net.*;
public class Client {
public static Socket socket = null;
public static Thread t1;
public static void main(String[] args) {
try {
System.out.println("Demande de connexion");
socket = new Socket("127.0.0.1",2009);
System.out.println("Connexion tablie avec le serveur, authentifica
tion :"); // Si le message s'affiche c'est que je suis connect
t1 = new Thread(new Connexion(socket));
t1.start();
} catch (UnknownHostException e) {
System.err.println("Impossible de se connecter l'adresse "+socket.g
etLocalAddress());
} catch (IOException e) {
System.err.println("Aucun serveur l'coute du port "+socket.getLoca
lPort());
}
}
}
Connexion.java
import java.net.*;
import java.util.Scanner;
import java.io.*;
public class Connexion implements Runnable {
private Socket socket = null;
public static Thread t2;
public static String login = null, pass = null, message1 = null, messag
e2 = null, message3 = null;
private PrintWriter out = null;
Emission.java
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Scanner;
public class Emission implements Runnable {
private PrintWriter out;
private String login = null, message = null;
Reception.java
import java.io.BufferedReader;
import java.io.IOException;
public class Reception implements Runnable {
private BufferedReader in;
private String message = null;
public Reception(BufferedReader in){
this.in = in;
}
public void run() {
while(true){
try {
message = in.readLine();
System.out.println("Le serveur vous dit :" +message);
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
Lancez serveur.java et ensuite client.java, n'oubliez pas de crer un fichier pour le serveur
pour qu'il puisse y vrifier l'identit de ses clients, je l'ai nomm zero.txt : vous pouvez le
nommer comme vous le souhaitez, c'est votre guise.
Optimisation :
Pour ne pas dire qu'il en existe l'infini, plusieurs autres possibilits s'offrent vous, vous
pouvez :
rendre l'application client / client. Le serveur authentifie les deux clients et ces deux-l
pourront discuter ensemble sans que d'autres puissent y entrer : grosso modo raliser
un salon , comme on l'appelle ;
utiliser les bases de donnes pour la sauvegarde des messages et pour authentifier les
clients ;
raliser une interface graphique en swing ou en awt ;
Croyez-moi : lorsque vous matriserez les sockets en utilisant les threads, rien ne sera plus
compliqu pour vous.
Bonne continuation tous ; surtout n'hsitez pas l'amliorer et
envoyez-moi un MP pour m'exposer votre travail.
Le mode UDP est plus rapide que le mode TCP mais c'est une communication non fiable, car
on ne se proccupe pas du rsultat de la rception du rcepteur, il est donc moins utilis.
Maintenant que vous savez manier les sockets, le mode UDP ne devrait pas vous poser de
problme
.
Je vous remercie d'avoir lu le tutoriel, il est prsent termin. J'espre que vous avez bien
suivi
la prochaine pour un autre tutoriel client/serveur ! La technologie RMI (Remote Method
Invocation) ! Qui vous permettra de mieux comprendre la nature et la fonction des EJB
(Entreprise JavaBeans) qui reprsente l'tendard de la plate-forme J2EE !
Je remercie :