Vous êtes sur la page 1sur 11

1.

Introduction
Depuis son origine, Java fournit plusieurs classes et interfaces destinées à faciliter
l'utilisation du réseau par programmation.

Le modèle OSI (Open System Interconnexion) propose un découpage en sept couches


des différents composants qui permettent la communication sur un réseau.

Le protocole IP est un protocole de niveau réseau qui permet d'échanger des paquets
d'octets appelés datagrammes. Ce protocole ne garantit pas l'arrivée à bon port des messages.
Cette fonctionnalité peut être implémentée par la couche supérieure, comme par exemple avec
TCP. Un datagramme IP est l'unité de transfert à ce niveau. Cette série d'octets contient les
informations du message, un en tête (adresse source de destination, ...). Mais aussi des
informations de contrôle. Ces informations permettent aux routeurs de faire transiter les
paquets sur l'internet.

La couche de transport est implémentée dans les protocoles UDP ou TCP. Ils
permettent la communication entre des applications sur des machines distantes.

La notion de service permet à une même machine d'assurer plusieurs communications


simultanément.

Le système des sockets est le moyen de communication inter-processus développé


pour l'Unix Berkeley (BSD). Il est actuellement implémenté sur tous les systèmes
d'exploitation utilisant TCP/IP

2. Définitions
1. Une socket est le point de communication par lequel un thread peut émettre ou
recevoir des informations et ainsi elle permet la communication entre deux
applications à travers le réseau
2. La communication se fait sur un port particulier de la machine. Le port est une entité
logique qui permet d'associer un service particulier à une connexion.
3. Un port est identifié par un entier de 1 à 65535. Par convention les 1024 premiers sont
réservés pour des services standard (80 : HTTP, 21 : FTP, 25: SMTP, ...)

3. Gestion des adresses réseau en Java


Chaque machine de l'Internet est identifiée par une adresse ou un nom unique. Ces deux
entités sont gérées sous Java par la classe InetAddress dont voici quelque méthode :

Méthode Rôle
byte []getAddress() donne les 4 octets de l'adresse IP de l'instance InetAddress courante
String Renvoie l'adresse internet sous la forme d'une chaîne de caractères
getHostAddress()
String getHostName() donne le nom Internet de l'instance InetAddress courante
InetAddress Renvoie l'adresse internet associée au nom d'hote fourni en
getByName(String ) paramètre
InetAddress Renvoie l'adresse internet de la machine locale

1
getLocalHost()
InetAddress[] Renvoie un tableau des adresses internet associées au nom d'hote
getAllByName(String) fourni en paramètre

Exemple 01 Identifier la machine locale

import java.net.*;
public class localhost{
public static void main (String arg[]){
try{
InetAddress adresse=InetAddress.getLocalHost();
byte[] IP=adresse.getAddress();
System.out.print("IP=");
int i;
for(i=0;i<IP.length-1;i++) System.out.print(IP[i]+".");
System.out.println(IP[i]);
System.out.println("adresse="+adresse.getHostAddress());
System.out.println("nom="+adresse.getHostName());
System.out.println("identité="+adresse);
} catch (UnknownHostException e){
System.out.println ("Erreur getLocalHost : "+e);
}// fin try
}// fin main
}// fin class

Les résultats de l'exécution sont les suivants :

IP=127.0.0.1 adresse=127.0.0.1 nom=machine1 identité= machine1/127.0.0.1


Exemple 02 Identifier une machine quelconque
import java.net.*;
public class getbyname{
public static void main (String arg[]){
String nomMachine;
// on récupère l'argument
if(arg.length==0)
nomMachine="localhost";
else nomMachine=arg[0];
// on tente d'obtenir l'adresse de la machine
try{
InetAddress adresse=InetAddress.getByName(nomMachine);
System.out.println("IP : "+ adresse.getHostAddress());
System.out.println("nom : "+ adresse.getHostName());
System.out.println("identité : "+ adresse);
} catch (UnknownHostException e){
System.out.println ("Erreur getByName : "+e);
}// fin try
}// fin main
}// fin cla
Avec l'appel java getbyname, on obtient les résultats suivants :
IP : 127.0.0.1
nom : localhost

2
identité : localhost/127.0.0.1

4. La relation client-serveur
Souvent, la communication sur Internet est dissymétrique : la machine A initie une connexion
pour demander un service à la machine B : il précise qu'il veut ouvrir une connexion avec le
service SB1 de la machine B. Celle-ci accepte ou refuse. Si elle accepte, la machine A peut
envoyer ses demandes au service SB1. Celles-ci doivent se conformer au protocole de
dialogue compris par le service SB1. Un dialogue demande-réponse s'instaure ainsi entre la
machine A qu'on appelle machine cliente et la machine B qu'on appelle machine serveur.
L'un des deux partenaires fermera la connexion.

4.1. Architecture d'un client

L'architecture d'un programme réseau demandant les services d'une application serveur sera la
(suivante :

ouvrir la connexion avec le service SB1 de la machine B


si réussite alors
y tant que ce n'est pas fini
 lpréparer une demande
 l'émettre vers la machine B
 attendre et récupérer la réponse
 traiter
fin tant que
finsi

4.2. Architecture d'un serveur

L'architecture d'un programme offrant des services est la suivante :

ouvrir le service sur la machine locale

tant que le service est ouvert

 se mettre à l'écoute des demandes de connexion sur un port dit port d'écoute

3
 lorsqu'il y a une demande, la faire traiter par une autre tâche sur un autre
port dit port de service

fin tant que

Le programme serveur traite différemment la demande de connexion initiale d'un


client de ses demandes ultérieures visant à obtenir un service. Le programme n'assure pas le
service lui-même. S'il le faisait, pendant la durée du service il ne serait plus à l'écoute des
demandes de connexion et des clients ne seraient alors pas servis. Il procède donc autrement :
dès qu'une demande de connexion est reçue sur le port d'écoute puis acceptée, le serveur crée
une tâche chargée de rendre le service demandé par le client. Ce service est rendu sur un autre
port de la machine serveur appelé port de service. On peut ainsi servir plusieurs clients en
même temps

tant que le service n'a pas été rendu totalement

 attendre une demande sur le port de service


 lorsqu'il y en a une, élaborer la réponse
 transmettre la réponse via le port de service

fin tant que

Libérer le port de service

5.Utilisation du protocole TCP

TCP est un protocole qui permet une connexion de type point à point entre deux
applications. C'est un protocole fiable qui garantit la réception dans l'ordre d'envoi des
données.

5.1. La classe Socket

L'outil de base utilisé par les programmes communiquant sur Internet est la socket. Ce
mot anglais signifie "prise de courant". Il est étendu ici pour signifier "prise de réseau". Pour
qu'une application puisse envoyer et recevoir des informations sur le réseau Internet, il lui faut
une prise de réseau, une socket. Cet outil a été initialement créé dans les versions d'Unix de
l'université de Berkeley. Il a été porté depuis sur tous les systèmes Unix ainsi que dans le
monde Windows. Il existe également sur les machines virtuelles Java sous deux formes : la
classe Socket pour les applications clientes et la classe ServerSocket pour les applications
serveur. La classe socket dispose de constructeur et les méthodes ci-après

5.1.1.Constructeur

Socket(String host, int port) ouvre une connexion distante avec le port port de la machine
host.

4
5.1.2. Les méthodes

Méthodes rôle
int getLocalPort() rend le n° du port local utilisé par la socket
int getPort() rend le n° du port distant auquel la socket est connectée
InetAddress getLocalAdress() rend l'adresse InetAddress locale à laquelle la socket est liée
InetAddress getInetAdress() rend l'adresse InetAddress distante à laquelle la socket est
liée
InputStream getInputStream() rend un flux d'entrée permettant de lire les données
envoyées par le partenaire distant
OutputStream rend un flux de sortie permettant d'envoyer des données au
getOutputStream partenaire distant
void close() ferme la socket et ses flux d'E/S
String toString() rend une chaîne de caractères "représentant" la socket

5.1.3. Ouverture d'une connexion avec une machine Serveur

Pour qu'une machine A ouvre une connexion avec un service d'une machine B, il lui fallait
deux informations :

 l'adresse IP ou le nom de la machine B


 le numéro de port où officie le service désiré

pour ouvrir une connexion on utilise :

Socket(String host, int port);

Ce constructeur génère une exception dans différents cas :

 Mauvaise adresse ou mauvais nom de la machine


 Mauvais port
 Demande refusée
5.1.4. Envoyer des informations sur le réseau
On peut obtenir un flux d'écriture sur la socket avec la méthode :

OutputStream getOutputStream();

Tout ce qui sera envoyé dans ce flux sera reçu sur le port de service de la machine serveur. La
méthode println est plus pratique dans ces cas là. On transforme le flux de sortie
OutputStream en flux PrintWriter qui possède la méthode println

5.1.5.Lire des informations venant du réseau

On peut obtenir un flux de lecture des informations arrivant sur la socket avec la méthode :

InputStream getInputStream();
5
Tout ce qui sera lu dans ce flux vient du port de service de la machine serveur.

5.1.6. Fermeture de la connexion

On peut fermer la connexion en utilisant la méthode : void close();

Donc le programme exécuté par le client est donné comme suit :


Socket sClient=null;
try{
// on se connecte au service officiant sur le port P de la machine M
sClient=new Socket(M,P);
// on crée les flux d'entrée-sortie de la socket client
BufferedReader in=new BufferedReader(new
InputStreamReader(sClient.getInputStream()));
PrintWriter out=new PrintWriter(sClient.getOutputStream());
// boucle demande - réponse
boolean fini=false;
String demande;
String réponse;
while (! fini){
// on prépare la demande
demande=…
// on l'envoie
out.println(demande);
// on lit la réponse
réponse=in.readLine();
// on traite la réponse

}
// c'est fini
sClient.close();
} catch(Exception e){
// on gère l'exception}

5.2. La classe ServerSocket

Cette classe est destinée à la gestion des sockets coté serveur. Elle possède les constructeurs
et les méthodes ci-après :

5.2.1. Les constructeurs

Constructeurs Rôle
ServerSocket(int port) crée une socket d'écoute sur le numéro port port
ServerSocket(int port, idem mais fixe à count la taille de la file d'attente, c.a.d. le nombre
int count) maximal de connexions clientes mises en attente si le serveur est
occupé lorsque la connexion cliente arrive.
5.2.2. Les méthodes

Méthode Rôle
int getL :ocalPort() rend le n° du port d'écoute utilisé par la socket
InetAddress rend l'adresse InetAddress locale à laquelle la socket est liée
getInetAdress()
Socket accept() met le serveur en attente d'une connexion (opération bloquante).
A l'arrivée d'une connexion cliente, rend une socket à partir de

6
laquelle sera rendu le service au client.
void close() ferme la socket et ses flux d'E/S libère les ressources qui lui sont
associées

5.2.3. Ouverture du service

Elle se fait avec l’un des deux constructeurs comme suit :

ServerSocket(int port);
ServerSocket(int port, int count); // count =50 par défaut
5.2.4. Acceptation d'une demande de connexion
Lorsqu’un client fait une demande de connexion sur le port d'écoute du service, le serveur
l'accepte avec la méthode : Socket accept();
Cette méthode rend une instance de Socket : c'est la socket de service, celle à travers laquelle
le service sera rendu, le plus souvent par une autre tâche. La méthode peut générer une
exception.
5.2.5. Lecture/Ecriture via la socket de service
Même chose que la partie client
5.2.6. Identifier le client
Une fois la socket de service obtenue, le client peut être identifié avec la méthode:
InetAddress getInetAddress()
Donc le programme exécuté par le serveur est :

SocketServer sEcoute=null;
try{
// ouverture du service
int portEcoute=…
int maxConnexions=…
sEcoute=new ServerSocket(portEcoute,maxConnexions);
// traitement des demandes de connexion
boolean fini=false;
Socket sService=null;
while( ! fini){

7
// attente et acceptation d'une demande
sService=sEcoute.accept();
// le service est rendu par une autre tâche à laquelle on passe la
socket de service
new Service(sService).start();
// on se remet en attente des demandes de connexion
}
// c'est fini - on clôt le service
sEcoute.close();
} catch (Exception e){
// on traite l'exception

}

La classe Service est un thread qui pourrait être sous la forme suivante:

public class Service extends Thread{


Socket sService; // la socket de service
public Service(Socket S){
sService=S;
}
public void run(){
try{
// on crée les
BufferedReader i flux d'entrée-sortien=new BufferedReader(new
InputStreamReader(sService.getInputStream()));
PrinttWriter out=new PrintWriter(sService.getOutputStream(),true);
// boucle demande - réponse
boolean fini=false;
String demande;
String réponse;
while (! fini){
// on lit la demande
demande=in.readLine();
// on la traite

// on prépare la réponse
réponse=…
// on l'envoie
out.println(réponse);

}
// c'est fini
sService.close();} catch(Exception e){
// on gère l'exception }// try } // run }

6. Utilisation du protocole UDP

UDP est un protocole basé sur IP qui permet une connexion de type point à point ou
de type multi-point. C'est un protocole qui ne garanti pas l'envoi dans l'ordre fourni des
données. En contre partie, ce protocole offre de bonnes performances car il est très rapide.
Pour utiliser le protocole UDP, java défini deux classes DatagramSocket et DatagramPacket

6.1. La classe DatagramSocket


Cette classe crée un Socket qui utilise le protocole UDP (Unreliable Datagram
Protocol) pour émettre ou recevoir des données. Cette classe possède plusieurs constructeurs :

6.1.1. Les constructeurs

8
constructeur Rôle
DatagramSocket() Créé une socket attachée à toutes les adresses IP de la machine
et un à des ports libres sur la machine
DatagramSocket(int) Créé une socket attachée à toutes les adresses IP de la machine
et au port précisé en paramètre
DatagramSocket(int, Créé une socket attachée à adresse IP et au port précisé en
InetAddress) paramètre

Remarque
Tous les constructeurs peuvent lever une exception de type SocketException: si le port précisé
est déjà utilisé lors de l'instanciation de l'objet DatagramSocket

6.1.2. Les méthodes


La classe DatagramSocket définit méthodes ci-après

Méthodes Rôles
close() Fermer la Socket et ainsi libérer le port
receive(DatagramPacket) Recevoir des données a partir d’une socket
send(DatagramPacket) Envoyer des données
int getPort() Renvoie le port associé au socket
void setSoTimeout(int) Préciser un timeout d'attente pour la réception d'un message

Remarque
un objet DatagramSocket ne possède pas de timeout lors de l'utilisation de la méthode
receive(). La méthode bloque donc l'exécution de l'application jusqu'à la réception d'un packet
de données. La méthode setSoTimeout() permet de préciser un timeout en millisecondes. Une
fois ce délai écoulé sans réception d'un paquet de données, la méthode lève une exception du
type SocketTimeoutException

6.2.La classe DatagramPacket


Cette classe encapsule une adresse internet, un port et les données qui sont échangées grâce à
un objet de type DatagramSocket. Elle possède les constructeurs et les methodes ci-après

6.2.1. Les constructeurs

Constructeur Rôle
DatagramPacket(byte Encapsule des paquets en réception dans un tampon
tampon[], int taille)
DatagramPacket(byte Encapsule des paquets en émission à destination
port[], int taille, d'une machine
InetAddress adresse,
int port )

6.2.2. Les méthodes

Méthodes Rôle

9
InetAddress getAddress () Renvoie l'adresse du serveur
byte[] getData() Renvoie les données contenues dans le paquet
int getPort () Renvoie le port
int getLength () Renvoie la taille des données contenues dans le paquet
setData(byte[]) Mettre à jour les données contenues dans le paquet

6.2.3. Exemple de client /serveur avec le protocole UDP

import java.io.*; Programme


import java.net.*; Serveur
public class TestServeurUDP {
final static int port = 9632;
final static int taille = 1024;
static byte buffer[] = new byte[taille];
public static void main(String argv[]) throws Exception {

DatagramSocket socket = new DatagramSocket(port);


String donnees = "";
String message = "";
int taille = 0;
System.out.println("Lancement du serveur");
while (true) {
DatagramPacket paquet = new DatagramPacket(buffer, buffer.length);
DatagramPacket envoi = null;
socket.receive(paquet);
System.out.println("\n"+paquet.getAddress());
taille = paquet.getLength();
donnees = new String(paquet.getData(),0, taille);
System.out.println("Donnees reçues = "+donnees);
message = "Bonjour "+donnees;
System.out.println("Donnees envoyees = "+message);
envoi = new DatagramPacket(message.getBytes(),
message.length(), paquet.getAddress(), paquet.getPort());
socket.send(envoi);
}
}}

import java.io.*; Programme


import java.net.*;
Client
public class TestClientUDP {

final static int port = 9632;

final static int taille = 1024;

static byte buffer[] = new byte[taille];

10
public static void main(String argv[]) throws Exception {

try {

InetAddress serveur = InetAddress.getByName(argv[0]);

int length = argv[1].length();

byte buffer[] = argv[1].getBytes();

DatagramSocket socket = new DatagramSocket();

DatagramPacket donneesEmises = new DatagramPacket(buffer, length,


serveur, port);

DatagramPacket donneesRecues = new DatagramPacket(new byte[taille],


taille);

socket.setSoTimeout(30000);

socket.send(donneesEmises);

socket.receive(donneesRecues);

System.out.println("Message : " + new


String(donneesRecues.getData(),

0, donneesRecues.getLength()));

System.out.println("de : " + donneesRecues.getAddress() + ":" +

donneesRecues.getPort());

} catch (SocketTimeoutException ste) {

System.out.println("Le delai pour la reponse a expire");

} catch (Exception e) {

e.printStackTrace();

}}}

11