Sockets et client-serveur
Ce que ce chapitre apporte 5 points
- Décrire l'architecture client-serveur et la répartition des rôles.
- Définir un socket et nommer les éléments qui identifient une extrémité.
- Comparer TCP et UDP et savoir lequel choisir, ce que le chapitre de réseau sur le transport et les noms établit du côté du protocole.
- Expliquer pourquoi un flux d'octets impose de délimiter les messages.
- Décrire l'enchaînement des appels côté serveur et côté client.
L'architecture client-serveur
Dans une architecture client-serveur, un programme dit serveur attend des demandes et y répond ; un ou plusieurs programmes dits clients émettent ces demandes.
La dissymétrie porte sur l'initiative. Le serveur ne connaît pas ses clients à l'avance et ne les contacte jamais spontanément : il écoute et réagit. Le client connaît l'adresse du serveur et déclenche l'échange.
Cette répartition explique l'ordre des opérations. Le serveur doit être en écoute avant qu'un client ne se connecte, et il doit pouvoir traiter plusieurs clients, ce qui ramène aux threads du chapitre Threads et synchronisation du parcours Systèmes d'exploitation.
Un client envoie deux messages TCP à la suite. Que reçoit le serveur ?
Le socket
Un socket est le point d'accès par lequel un programme émet et reçoit des données sur un réseau. Une extrémité de communication est identifiée par une adresse IP, un numéro de port et un protocole de transport.
L'adresse désigne la machine, le port désigne le programme sur cette machine. Un serveur web occupe habituellement le port 443, un serveur de base de données un autre : c'est ce qui permet à une même machine d'héberger plusieurs services.
Une connexion établie se caractérise par quatre valeurs : adresse et port de la source, adresse et port de la destination. C'est ce qui permet à un serveur de distinguer deux clients venant de la même machine.
TCP et UDP
| TCP | UDP | |
|---|---|---|
| Connexion | établie avant l'échange | aucune |
| Livraison | garantie, retransmission en cas de perte | sans garantie |
| Ordre | préservé | non garanti |
| Unité | flux d'octets continu | datagrammes délimités |
| Coût | plus élevé | minimal |
| Emploi | fichiers, requêtes, tout ce qui doit arriver entier | flux audio ou vidéo, découverte, mesures |
Deux envois consécutifs peuvent être reçus en une seule lecture, et un envoi de mille octets peut être reçu en trois morceaux. Le protocole applicatif doit donc porter lui-même la délimitation des messages.
Délimiter les messages
Trois techniques existent, et le choix a des conséquences.
Un délimiteur, souvent un saut de ligne, marque la fin d'un message. Simple, lisible, mais interdit au contenu de comporter ce caractère sans échappement.
Une longueur en préfixe annonce le nombre d'octets à lire. C'est la solution générale, qui accepte n'importe quel contenu binaire.
Une taille fixe convient quand tous les messages ont la même structure.
Le symptôme classique est un message tronqué ou deux messages collés, apparaissant sous charge et jamais en test.
Quelle technique de délimitation accepte n'importe quel contenu binaire ?
La séquence des appels
L'ordre est imposé par la nature de la connexion, et il se retient facilement.
Le serveur commence seul : il crée son socket, l'associe à une adresse et à un port, puis se met en écoute. Rien ne circule encore. Les échanges commencent quand un client se présente.
- Client vers Serveur : demande de connexion.
- Serveur vers Client, en réponse : connexion acceptée.
- Client vers Serveur : envoyer les données.
- Serveur vers Client, en réponse : réponse.
- Client vers Serveur : fermer.
L'appel qui accepte une connexion est bloquant : il attend qu'un client se présente. Il rend un nouveau socket, propre à cette connexion, tandis que le socket d'écoute reste disponible pour les suivants.
Le lien avec le chapitre précédent. Un serveur qui traite un client à la fois fait attendre tous les autres pendant la durée de l'échange. Pour servir plusieurs clients, il faut soit un thread par connexion, soit des entrées-sorties asynchrones.
Le thread par connexion est simple à écrire et ne passe pas l'échelle : quelques milliers de connexions coûtent quelques milliers de piles. Les serveurs à forte charge emploient l'asynchrone, où un petit nombre de threads gère un grand nombre de connexions en attente.
1.Qu'identifie le numéro de port d'une extrémité de communication ?
2.Que rend l'appel qui accepte une connexion côté serveur ?
Ce que ce chapitre ne traite plus
Les deux sections qui suivaient portaient sur les conteneurs et sur la chaîne d'intégration continue. Elles ont été retirées le jour où l'atelier de développement a rejoint ce parcours, parce que chacune de ces notions y a désormais son chapitre entier :
- Conteneurs et images construit une image couche par couche, et montre ce que coûte l'ordre des instructions.
- L'intégration continue déroule une chaîne complète, de la fusion à la mise en ligne.
Un résumé de dix lignes à côté d'un chapitre qui traite la même chose n'aide personne : il se périme sans qu'on le relise, et il donne au lecteur l'impression d'avoir fait le tour.
Mettre en pratique
Pourquoi ne peut-on pas supposer qu'un envoi TCP correspond à une réception ?
Parce que TCP transporte un flux d'octets et non des messages. Il garantit l'ordre et l'absence de perte, rien de plus.
Le système regroupe ou découpe les envois selon la taille des paquets, la congestion et ses propres optimisations. Deux envois peuvent arriver dans une seule lecture, un envoi peut arriver en plusieurs.
Le protocole applicatif doit donc délimiter lui-même : par un caractère de fin, par une longueur en préfixe, ou par une taille fixe.
UDP se comporte différemment : un datagramme est reçu entier ou pas du tout, ce qui règle la délimitation mais supprime les garanties de livraison et d'ordre.
Un serveur de fichiers doit-il utiliser TCP ou UDP ?
TCP, sans hésitation.
Un fichier doit arriver entier, dans l'ordre et sans altération. UDP ne garantit aucun des trois : des datagrammes peuvent se perdre, arriver dans le désordre ou être dupliqués.
Employer UDP obligerait à réimplémenter les accusés de réception, la retransmission et le réordonnancement, c'est-à-dire à réécrire TCP, moins bien.
UDP se justifie quand la perte est préférable au retard : un flux vidéo continue en sautant une image, alors qu'attendre la retransmission produirait un gel.
Que se passe-t-il si un serveur traite les clients un par un ?
Chaque client attend que tous les précédents soient servis. Le débit s'effondre dès que les échanges durent, et un client lent bloque tous les autres.
La solution simple est un thread par connexion. Elle fonctionne jusqu'à quelques centaines de clients, puis le coût des piles et des commutations devient dominant.
Au-delà, on emploie des entrées-sorties asynchrones : un petit nombre de threads gère un grand nombre de connexions, chacune ne consommant un thread que pendant le traitement effectif, pas pendant l'attente.
C'est le même arbitrage que celui du chapitre sur les processus, entre simplicité d'écriture et passage à l'échelle.
Chapitre révisé en octobre 2026 · Une erreur dans ce chapitre ?
Dans la bibliothèque d'exercices
Ce qui identifie une connexion, le flux TCP, et les couches d'une image.
Tous les exercices sur sockets et conteneurs