Vous êtes sur la page 1sur 35

Sockets et JAVA NIO

KEBIRA AZBEG - SYSTÈMES RÉPARTIS - 2023/2024 1


Introduction
• La communication réseau est le processus par lequel des ordinateurs
ou des dispositifs interagissent entre eux en partageant des données via
un réseau, qu'il s'agisse d'un réseau local ou d'un réseau étendu.
• Cette communication peut être réalisée à travers divers protocoles et
technologies, permettant aux machines de s'échanger des informations
et de collaborer, indépendamment de leur emplacement physique.
• La communication réseau est essentielle pour permettre aux
différentes parties d'une application distribuée de travailler ensemble
de manière coordonnée.
• La manière la plus ancienne de communiquer entre applications
réparties a été l'utilisation des sockets.

KEBIRA AZBEG - SYSTÈMES RÉPARTIS - 2023/2024 2


Communication en réseau
• Les sockets fournissent une interface d’accès, à partir d’un hôte, aux
interfaces de transport, notamment TCP et UDP.
• Les sockets sont des ports de communication ouverts au niveau des
couches de réseau du système d'exploitation, et permettant de faire
passer des flux (streams) d'octets.
• Les sockets permettent de communiquer en point à point en mode
client/serveur.
• La socket serveur va accepter des connexions sur un port de
communication donné, puis va analyser le flux obtenu ou écrire dans le
flux.
• 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.

KEBIRA AZBEG - SYSTÈMES RÉPARTIS - 2023/2024 3


Communication en réseau
Il existe essentiellement deux protocoles de communication par socket:
• TCP (Transmission Control Protocol): est dit fiable car il nécessite un
point de rendez-vous entre le client et le serveur au moment de la
connexion du client (on est assuré que les deux parties sont présentes
au moment de la communication).
• UDP (User Datagram protocol): il n'existe pas de point de rendez-vous,
et donc le serveur n'est pas assuré que l'information a été reçue
réellement.

KEBIRA AZBEG - SYSTÈMES RÉPARTIS - 2023/2024 4


Communication avec TCP
La classe ServerSocket :
• La classe ServerSocket est utilisée côté serveur : elle attend
simplement les appels du ou des clients.
• C'est un objet du type Socket qui prend en charge la transmission des
données.
• Un objet de cette classe est associé à un port sur lequel il va attendre
les connexions d'un client.
• Généralement, à l'arrivée d'une demande de connexion, un thread est
lancé pour assurer le dialogue avec le client sans bloquer les connexions
des autres clients.

KEBIRA AZBEG - SYSTÈMES RÉPARTIS - 2023/2024 5


Communication avec TCP
La classe ServerSocket :
La classe ServerSocket possède plusieurs constructeurs dont les
principaux sont :
• ServerSocket() : Constructeur par défaut.
• ServerSocket(int) : Créer une socket sur le port fourni en paramètre.
• ServerSocket(int, int) : Créer une socket sur le port et avec la taille
maximale de la file fournis en paramètres.
Tous ces constructeurs peuvent lever une exception de type IOException.

KEBIRA AZBEG - SYSTÈMES RÉPARTIS - 2023/2024 6


Communication avec TCP
La classe ServerSocket :
Quelques méthodes de la classe ServerSocket:
• Socket accept(): Attendre une nouvelle connexion. Si un client tente de
communiquer avec le serveur, la méthode accept() renvoie une socket
qui encapsule la communication avec ce client.
• void close(): Fermer la socket.

KEBIRA AZBEG - SYSTÈMES RÉPARTIS - 2023/2024 7


Communication avec TCP
La classe Socket :
• Les sockets implémentent le protocole TCP.
• La classe contient les méthodes de création des flux d'entrée et de
sortie correspondants.
• La classe encapsule la connexion à une machine distante par le réseau.
Elle gère la connexion, l'envoi de données, la réception de données et la
déconnexion.

KEBIRA AZBEG - SYSTÈMES RÉPARTIS - 2023/2024 8


Communication avec TCP
La classe Socket :
La classe Socket possède plusieurs constructeurs dont les principaux
sont :
• Socket() : Constructeur par défaut.
• Socket(String, int) : Créer une socket sur la machine dont le nom et le
port sont fournis en paramètres.
• Socket(InetAddress, int) : Créer une socket sur la machine dont
l'adresse IP et le port sont fournis en paramètres.

KEBIRA AZBEG - SYSTÈMES RÉPARTIS - 2023/2024 9


Communication avec TCP
La classe Socket :
Quelques méthodes de la classe Socket:
• InetAddress getInetAddress(): Renvoie l'adresse IP à laquelle la socket
est connectée.
• void close(): Fermer la socket.
• InputStream getInputStream(): Renvoie un flux en entrée pour recevoir
les données de la socket.
• OutputStream getOutputStream(): Renvoie un flux en sortie pour
émettre les données de la socket.
• int getPort(): Renvoie le port utilisé par la socket.

KEBIRA AZBEG - SYSTÈMES RÉPARTIS - 2023/2024 10


Communication avec TCP
• La classe ServerSocket: créer des sockets côté serveur.
• La classe Socket: créer des sockets clients.
• Les sockets sont basés sur des flux d'E/S, ce qui signifie que vous
pouvez utiliser des InputStream et des OutputStream pour lire et écrire
des données.

KEBIRA AZBEG - SYSTÈMES RÉPARTIS - 2023/2024 11


Communication avec TCP
Voici les étapes de base pour créer un client-serveur en utilisant des
sockets en Java :
1. Côté serveur :
• Créez une ServerSocket en spécifiant le port d'écoute.
• Acceptez les connexions entrantes en utilisant la méthode accept().
• Créez une Socket pour gérer la communication avec le client.
• Lisez et écrivez des données sur le socket pour communiquer avec le client.

2. Côté client :
• Créez une Socket en spécifiant l'adresse IP et le port du serveur.
• Lisez et écrivez des données sur le socket pour communiquer avec le serveur.

KEBIRA AZBEG - SYSTÈMES RÉPARTIS - 2023/2024 12


Communication avec TCP
Exemple: Côté serveur
import java.io.*;
import java.net.*;
public class ChatServer {
public static void main(String[] args) throws IOException {
ServerSocket serverSocket = new ServerSocket(12346); // Crée un serveur
écoutant sur le port 12346
System.out.println("Le serveur de chat est prêt. Attente de connexions...");
Socket clientSocket = serverSocket.accept(); // Attend qu'un client se connecte
InputStreamReader inputReader = new InputStreamReader(clientSocket.getInputStream());
BufferedReader in = new BufferedReader(inputReader);
PrintWriter out = new PrintWriter(clientSocket.getOutputStream(), true);
String message;
while ((message = in.readLine()) != null) {
System.out.println("Client : " + message);
out.println("Serveur : Message reçu : " + message);
}
clientSocket.close();
serverSocket.close();
}
}
KEBIRA AZBEG - SYSTÈMES RÉPARTIS - 2023/2024 13
Communication avec TCP
Exemple: Côté client
import java.io.*;
import java.net.*;
public class ChatClient {
public static void main(String[] args) throws IOException {
Socket clientSocket = new Socket("localhost", 12346); // Se connecte au serveur sur
le port 12346
InputStreamReader inputReader = new InputStreamReader(clientSocket.getInputStream());
BufferedReader in = new BufferedReader(inputReader);
PrintWriter out = new PrintWriter(clientSocket.getOutputStream(), true);
BufferedReader consoleIn = new BufferedReader(new InputStreamReader(System.in));
String message;
while (true) {
System.out.print("Client : ");
message = consoleIn.readLine();
out.println(message);
String response = in.readLine();
System.out.println(response);
}
}
}
KEBIRA AZBEG - SYSTÈMES RÉPARTIS - 2023/2024 14
Utilisation des threads
• L'inconvénient du modèle précédent est qu'il ne peut traiter qu'une
connexion à la fois.
• Pour pouvoir traiter plusieurs connexions simultanément, il faut créer
un nouveau thread contenant les traitements à réaliser sur la socket.
• Le serveur va lancer plusieurs threads en parallèle afin de traiter les
requêtes de manière simultanée.

KEBIRA AZBEG - SYSTÈMES RÉPARTIS - 2023/2024 15


Utilisation des threads
• Afin de rendre le code plus modulaire, on crée une classe auxiliaire, le
Handler, qui hérite de Thread et définit la gestion de la requête.
• Ce Handler va prendre en paramètre la socket et gérer la requête :
Syntaxe
public class Handler extends Thread {
private Socket clientSocket;

public Handler(Socket clientSocket) {


this.clientSocket = clientSocket;
}
public void run() {
// Code de gestion de la requête pour ce client
// Utilisation de la socket client pour envoyer et recevoir des données
// Gestion des exceptions, lecture, écriture, etc.
clientSocket.close(); // Assurez-vous de fermer la socket lorsque vous avez terminé.
}
}
KEBIRA AZBEG - SYSTÈMES RÉPARTIS - 2023/2024 16
Utilisation des threads
Exemple: Handler
public class ClientHandler extends Thread {
private Socket clientSocket;
public ClientHandler(Socket socket) {
this.clientSocket = socket;
}
public void run() {
try {
BufferedReader in = new BufferedReader(new
InputStreamReader(clientSocket.getInputStream()));
out = new PrintWriter(clientSocket.getOutputStream(), true);
while (true) {
String message = in.readLine();
if (message == null) {
break;
}
System.out.println("Message reçu : " + message);}
} catch (IOException e) {
e.printStackTrace();
} finally {
clientSocket.close();
}} KEBIRA AZBEG - SYSTÈMES RÉPARTIS - 2023/2024 17
Utilisation des threads
Exemple: Côté serveur
import java.io.*;
import java.net.*;
public class ChatServer {
public static void main(String[] args) {
try {
ServerSocket serverSocket = new ServerSocket(12355);
System.out.println("Le serveur de chat est en cours d'exécution et en
attente de clients...");
while (true) {
Socket clientSocket = serverSocket.accept();
System.out.println("Client connecté : " + clientSocket);
ClientHandler clientHandler = new ClientHandler(clientSocket);
clientHandler.start();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
KEBIRA AZBEG - SYSTÈMES RÉPARTIS - 2023/2024 18
Utilisation des threads
Exemple: Côté client
public class ChatClient {
public static void main(String[] args) {
try {
Socket socket = new Socket("localhost", 12355);
PrintWriter out = new PrintWriter(socket.getOutputStream(), true);
BufferedReader in = new BufferedReader(new
InputStreamReader(socket.getInputStream()));
BufferedReader userInput = new BufferedReader(new
InputStreamReader(System.in));
System.out.println("Connecté au serveur. Vous pouvez commencer à envoyer des
messages.");
while (true) {
String message = userInput.readLine();
out.println(message);
String response = in.readLine();
System.out.println("Réponse du serveur : " + response);
}
} catch (IOException e) {
e.printStackTrace();
}}}
KEBIRA AZBEG - SYSTÈMES RÉPARTIS - 2023/2024 19
Communication avec UDP
• Le mode UDP est un mode non connecté, qui va permettre de gagner
en performance.
• Ce protocole nécessite de segmenter l'information en paquets et il est
très utilisé dans le monde multimédia.
Quelles classes utiliser ?
• il faut utiliser les classes DatagramPacket et DatagramSocket.
• Ces objets sont initialisés différemment selon qu’ils sont utilisés pour
envoyer ou recevoir des paquets.

KEBIRA AZBEG - SYSTÈMES RÉPARTIS - 2023/2024 20


Communication avec UDP
Envoi d’un Datagramme (Client):
1. Création de la Socket : Créez une instance de DatagramSocket pour le client.

DatagramSocket clientSocket = new DatagramSocket();

2. Préparation des Données : Convertissez les données à envoyer en tableau de


bytes (byte[]).

String message = "Hello, server!";


byte[] sendData = message.getBytes();

KEBIRA AZBEG - SYSTÈMES RÉPARTIS - 2023/2024 21


Communication avec UDP
Envoi d’un Datagramme (Client):
3. Création du DatagramPacket : Créez un objet DatagramPacket avec les
données à envoyer, l'adresse IP du serveur et le port du serveur.

InetAddress serverAddress = InetAddress.getByName("server_ip");


int serverPort = 4666;
DatagramPacket sendPacket = new DatagramPacket(sendData, sendData.length,
serverAddress, serverPort);

4. Envoi du DatagramPacket : Utilisez la méthode send de la DatagramSocket


pour envoyer le paquet au serveur.

clientSocket.send(sendPacket);

KEBIRA AZBEG - SYSTÈMES RÉPARTIS - 2023/2024 22


Communication avec UDP
Réception d’un Datagramme (Serveur):
1. Création de la Socket Serveur: Créez une instance de DatagramSocket pour le
serveur, en spécifiant le port sur lequel écouter.

DatagramSocket serverSocket = new DatagramSocket(4666);

2. Préparation du DatagramPacket pour la Réception : Créez un objet


DatagramPacket pour recevoir les données du client.

byte[] receiveData = new byte[1024];


DatagramPacket receivePacket = new DatagramPacket(receiveData, receiveData.length);

KEBIRA AZBEG - SYSTÈMES RÉPARTIS - 2023/2024 23


Communication avec UDP
Réception d’un Datagramme (Serveur):
3. Attente de la Réception : Utilisez la méthode receive de la DatagramSocket
pour attendre la réception d'un datagramme du client.

serverSocket.receive(receivePacket);

4. Extraction des Données : Extrayez les données du DatagramPacket.

byte[] clientData = receivePacket.getData();


int length = receivePacket.getLength();
String clientMessage = new String(clientData, 0, length);

5. Réponse au Client (si nécessaire) : Si nécessaire, créez une réponse et


envoyez-la au client de la même manière que dans l'étape d'envoi.

KEBIRA AZBEG - SYSTÈMES RÉPARTIS - 2023/2024 24


JAVA NIO

KEBIRA AZBEG - SYSTÈMES RÉPARTIS - 2023/2024 25


JAVA NIO
• La bibliothèque Java NIO (New I/O) est une nouvelle bibliothèque
introduite dans le JDK 1.4.
• Elle fournit des fonctionnalités pour les opérations d'entrée/sortie non
bloquantes permettant d'optimiser les performances des
entrées/sorties en Java.
• Ainsi une copie de fichier pourra être jusqu'à dix fois plus rapide, au
prix d'une gestion plus fine des ressources, et donc d'un code un peu
plus complexe.
• JAVA NIO gère les données en bloc, contrairement à IO qui les traite par
flux.

KEBIRA AZBEG - SYSTÈMES RÉPARTIS - 2023/2024 26


JAVA NIO
Canaux et tampons:
Les canaux (channels) et les tampons (buffers) sont au centre de
l'architecture J a v a . n i o . * .
• Les buffers :
• sont des zones de mémoire dans lesquelles les données peuvent être lues
ou écrites.
• sont utilisés pour stocker temporairement les données lors des opérations
d'entrée/sortie.
• peuvent être utilisés avec les canaux pour faciliter la manipulation des
données.
• Les Channels :
• représentent une connexion vers une source ou une destination de données.
• peuvent être associés à des fichiers, des sockets, des pipes, etc.
• peuvent être non bloquants, ce qui signifie qu'ils ne bloquent pas l'exécution
du programme pendant que les données sont lues ou écrites.

KEBIRA AZBEG - SYSTÈMES RÉPARTIS - 2023/2024 27


JAVA NIO - Buffers
• Types de tampons:
• Il existe plusieurs types de tampons en Java NIO, dont les plus couramment
utilisés sont ByteBuffer, CharBuffer, ShortBuffer, IntBuffer, LongBuffer,
FloatBuffer, et DoubleBuffer.
• Chacun de ces tampons est spécialisé pour stocker un type particulier de
données.
• implémentent tous l'interface Buffer.
• Allocation de tampons:
• Vous pouvez allouer un tampon en utilisant la méthode statique allocate().
• Exemple: ByteBuffer buffer = ByteBuffer.allocate(1024);
=> permet d’allouer un tampon de 1024 octets.
• Modes du tampon:
• Un tampon peut être en mode lecture ou écriture.
• La méthode flip() est utilisée pour basculer entre ces deux modes.

KEBIRA AZBEG - SYSTÈMES RÉPARTIS - 2023/2024 28


JAVA NIO - Buffers
• Propriétés d’un tampon: l’état d’un tampon est définit par 4 propriétés
• capacity : nombre d'éléments - invariable - fixé à la création .
• position : index du premier élément accessible. L'endroit actuel où les
lectures et écritures se produiront.
• limit : index du premier élément non accessible. La position maximale
jusqu'à laquelle vous pouvez lire ou écrire.
• mark : la position de réinitialisation lors du reset.

• Méthodes de manipulation:
• put() : pour écrire des données,
• get() : pour lire des données,
• flip() : pour basculer entre les modes,
• clear() : pour effacer le tampon en mode écriture,
• compact() : pour compacter le tampon en mode écriture.

KEBIRA AZBEG - SYSTÈMES RÉPARTIS - 2023/2024 29


JAVA NIO - Channels
• Types de canaux : Il existe différents types de canaux, chacun
correspondant à un type spécifique de source ou de destination.
• FileChannel : pour les opérations sur les fichiers .
• SocketChannel : pour la communication sur un réseau via TCP.
• DatagramChannel : pour la communication via UDP.
• Méthodes de lecture/écriture : Les canaux fournissent des méthodes
pour lire à partir de et écrire dans des tampons (buffers).
• read(buffer) : lecture
• write(buffer) : écriture
• Mode non bloquant :
• ce qui signifie qu'ils ne bloquent pas l'exécution du programme pendant que
les opérations d'entrée/sortie sont en cours.
• permet de gérer plusieurs canaux simultanément sans avoir besoin de
threads dédiés pour chaque canal.

KEBIRA AZBEG - SYSTÈMES RÉPARTIS - 2023/2024 30


Sockets avec NIO
• La communication par sockets asynchrone:
• fait référence à un style de programmation où les opérations de
communication réseau ne bloquent pas le flux d'exécution principal du
programme.
• le programme peut continuer à effectuer d'autres tâches ou à répondre à
d'autres événements pendant que les opérations de communication réseau
sont en cours.

=> Dans le contexte de la programmation réseau en Java, cela est


généralement réalisé en utilisant l'API Java NIO et en particulier les sélecteurs
(Selector).

KEBIRA AZBEG - SYSTÈMES RÉPARTIS - 2023/2024 31


Sockets avec NIO
• Sélecteurs (Selectors) :
• Les sélecteurs permettent de surveiller plusieurs canaux non bloquants pour
déterminer lesquels sont prêts à effectuer des opérations d'entrée/sortie.
• Les sélecteurs facilitent la gestion de plusieurs canaux dans un seul thread,
en évitant d'avoir à utiliser un thread par canal.
• Pour créer un selecteur:

Selector selector = Selector.open();

KEBIRA AZBEG - SYSTÈMES RÉPARTIS - 2023/2024 32


Sockets avec NIO
• Ouverture d'un canal de socket pour le serveur et le configurer pour
être non bloquant :

ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();


serverSocketChannel.bind(new InetSocketAddress(4666));
serverSocketChannel.configureBlocking(false);

• Enregistrement du canal de serveur auprès du sélecteur:

serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);

KEBIRA AZBEG - SYSTÈMES RÉPARTIS - 2023/2024 33


Sockets avec NIO
• Attente de Canaux Prêts : utilisée pour attendre que l'un ou plusieurs
des canaux enregistrés soient prêts à effectuer une opération

int readyChannels = selector.select();

• Ensemble de Clés Sélectionnées: récupérer l'ensemble des clés de


sélection qui représentent les canaux prêts
if (readyChannels > 0) {
Set<SelectionKey> selectedKeys = selector.selectedKeys();
Iterator<SelectionKey> keyIterator = selectedKeys.iterator();
while (keyIterator.hasNext()) {
SelectionKey key = keyIterator.next();
// ... traitement des opérations pour ce canal ...
keyIterator.remove();
}
}
KEBIRA AZBEG - SYSTÈMES RÉPARTIS - 2023/2024 34
Sockets avec NIO
• Ouverture d'un canal de socket pour le client et le configurer pour
être non bloquant :

SocketChannel socketChannel = SocketChannel.open();


socketChannel.configureBlocking(false);

• Se connecter au serveur :

socketChannel.connect(new InetSocketAddress("localhost", 4666));

KEBIRA AZBEG - SYSTÈMES RÉPARTIS - 2023/2024 35

Vous aimerez peut-être aussi