Réseau : sockets client/serveur
Cours · programmation Java (école d'ingénieur), chapitre 16 · école d'ingénieur, informatique · le début du chapitre, la suite sur Adloun
Quand vous ouvrez une page web, votre navigateur (le client) envoie une demande à un programme qui tourne sur une machine distante (le serveur), qui lui renvoie la page. La messagerie, les jeux en ligne, les bases de données, les applications mobiles fonctionnent de la même façon : deux programmes, souvent sur deux machines, qui échangent des messages selon des règles convenues. Ce chapitre montre comment écrire en Java les deux côtés de cet échange, à l'aide des sockets.
À faire sur votre ordinateur
Les programmes de ce chapitre ouvrent des connexions réseau : ils ne tournent pas dans l'Éditeur Java du navigateur, mais avec un JDK installé sur votre ordinateur. Tous les exemples se contentent de la machine locale : on lance le serveur dans un terminal, le client dans un second terminal, et ils communiquent sans même passer par Internet.
Objectifs du chapitre
- Connaître le modèle client/serveur et le vocabulaire du réseau : adresse IP, port, TCP, UDP,
localhost. - Écrire un serveur TCP (
ServerSocket) et un client (Socket) qui échangent des lignes de texte. - Définir un petit protocole et le programmer des deux côtés.
- Servir plusieurs clients à la fois, un fil par client.
- Traiter les erreurs propres au réseau : connexion refusée, port occupé, délai d'attente dépassé.
- Savoir envoyer un datagramme UDP et télécharger une page web avec
HttpClient.
16.1 Le modèle client/serveur
Un serveur est un programme qui attend des demandes et y répond ; il tourne en permanence et peut servir de nombreux clients. Un client est un programme qui prend l'initiative de contacter un serveur, lui envoie des requêtes et reçoit ses réponses.
16.1.1 Adresses et ports
Pour joindre un programme sur le réseau, il faut deux informations :
- l'adresse IP de la machine, par exemple
192.168.1.20(IPv4, quatre nombres de à ) ou une adresse IPv6 plus longue. Un nom de domaine commewww.exemple.frest traduit en adresse IP par le DNS ; - le port, un entier de à , qui désigne un programme sur cette machine. Les ports inférieurs à sont réservés aux services standard (80 pour HTTP, 443 pour HTTPS, 22 pour SSH…) ; nos serveurs utiliseront des ports comme .
L'adresse 127.0.0.1, de nom localhost, désigne toujours la machine elle-même (la boucle locale) : un client et un serveur qui tournent sur le même ordinateur s'y retrouvent, sans réseau extérieur. La classe InetAddress représente une adresse :
import java.net.InetAddress;
import java.net.UnknownHostException;
/** Chapitre 16 — adresses IP et noms de machines. */
public class Adresses {
public static void main(String[] args) throws UnknownHostException {
InetAddress local = InetAddress.getByName("localhost");
System.out.println("localhost -> " + local.getHostAddress());
System.out.println("boucle locale -> " + InetAddress.getLoopbackAddress());
InetAddress ip = InetAddress.getByName("192.168.1.20"); // aucune résolution réseau
System.out.println("adresse lue -> " + ip.getHostAddress());
try {
InetAddress.getByName("machine-qui-n-existe-pas.invalid");
} catch (UnknownHostException e) {
System.out.println("nom inconnu -> " + e.getClass().getSimpleName());
}
}
}
localhost -> 127.0.0.1
boucle locale -> localhost/127.0.0.1
adresse lue -> 192.168.1.20
nom inconnu -> UnknownHostException
16.1.2 TCP et UDP
Deux protocoles de transport sont disponibles.
| TCP | UDP |
|---|---|
| connexion établie avant l'échange | pas de connexion |
| flot d'octets continu, dans les deux sens | messages indépendants (datagrammes) |
| fiable : rien n'est perdu, l'ordre est conservé | ni garantie de livraison, ni d'ordre |
| plus lent à établir | très léger, rapide |
| web, courrier, fichiers, bases de données | visioconférence, jeux, mesures |
La plupart des applications utilisent TCP ; c'est lui que nous étudierons d'abord.
Une socket (« prise ») est l'extrémité d'une connexion réseau, du point de vue d'un programme. En TCP, une connexion relie deux sockets ; chacune offre un flux d'entrée (ce que l'autre côté envoie) et un flux de sortie (ce que l'on envoie), exactement comme un fichier ouvert (chapitre 14).
16.2 Un premier serveur : l'écho
Le paquetage java.net fournit deux classes :
ServerSocket, côté serveur : on la crée sur un port, puisaccept()attend qu'un client se connecte et renvoie uneSocketreliée à ce client ;Socket, côté client :new Socket(hôte, port)établit la connexion avec le serveur.
De chaque côté, on obtient ensuite les flux avec getInputStream() et getOutputStream(), que l'on emboîte comme pour un fichier : un BufferedReader pour lire des lignes, un PrintWriter pour en écrire.
Notre premier serveur renvoie chaque ligne qu'il reçoit, précédée de « écho : ».
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.nio.charset.StandardCharsets;
/** Chapitre 16 — un serveur d'écho : il renvoie chaque ligne qu'il reçoit. */
public class ServeurEcho {
public static void main(String[] args) throws IOException {
int port = 5000;
try (ServerSocket serveur = new ServerSocket(port)) {
System.out.println("Serveur à l'écoute sur le port " + port);
while (true) {
try (Socket client = serveur.accept(); // attend un client
BufferedReader in = new BufferedReader(new InputStreamReader(client.getInputStream(), StandardCharsets.UTF_8));
PrintWriter out = new PrintWriter(new OutputStreamWriter(client.getOutputStream(), StandardCharsets.UTF_8), true)) {
System.out.println("Client connecté : " + client.getInetAddress().getHostAddress()
+ ", port " + client.getPort());
String ligne;
while ((ligne = in.readLine()) != null) { // null : le client a fermé
System.out.println("reçu : " + ligne);
out.println("écho : " + ligne);
}
System.out.println("Client déconnecté");
}
}
}
}
}
La suite du cours est sur Adloun
Le chapitre en entier, formules et figures comprises, avec le tuteur, les fiches, les QCM et les exercices.
Lire la suite du coursEn accès libre, sans inscription.