2026-09-07 — Programmation par socket
Contexte
Matière : _Reseaux · Type : cours · Source : support Chapitre 2 — La couche Application (Partie 4) Précédent : 2026-09-07 — Le protocole DNS
🎯 Objectifs de la séance
- Comprendre ce qu’est un socket et où il se situe dans la pile.
- Savoir écrire un couple client / serveur UDP en Python.
- Savoir écrire un couple client / serveur TCP en Python.
- Identifier les différences structurelles entre les deux, et leur origine protocolaire.
Partie 1 — Le socket
Application réseau
Une application réseau est composée de plusieurs processus qui communiquent par des messages.
Socket
Abstraction utilisée par l’interface de programmation située entre la couche application et la couche transport. C’est la porte par laquelle un processus envoie et reçoit des messages.
┌──────────────────────┐ ┌──────────────────────┐
│ Processus client │ │ Processus serveur │
├──────────────────────┤ ├──────────────────────┤
│ SOCKET │◀────────▶│ SOCKET │ ← API app/transport
├──────────────────────┤ ├──────────────────────┤
│ Transport (TCP/UDP) │ │ Transport (TCP/UDP) │
│ Réseau · Liaison │ │ Réseau · Liaison │
└──────────────────────┘ └──────────────────────┘
L’application de référence : conversion en majuscules
Le cours construit la même application avec les deux protocoles :
- Le client lit une ligne saisie au clavier.
- Il envoie ces données au serveur.
- Le serveur reçoit les données.
- Le serveur transforme les caractères en majuscules.
- Il renvoie la traduction au client.
- Le client reçoit la réponse et l’affiche.
Partie 2 — Sockets UDP
Le principe
Pas de connexion, donc pas d'implicite
Avec UDP, il n’existe aucune connexion entre client et serveur : ni établissement, ni négociation préalable. Conséquences directes sur le code :
- Le client doit joindre explicitement l’IP et le port du serveur à chaque envoi.
- Le serveur doit extraire l’IP et le port du client du datagramme reçu pour savoir à qui répondre.
Le schéma d’échange
Client Serveur
│ │
│ créer un socket UDP : │ créer un socket sur le port x :
│ socket(AF_INET, SOCK_DGRAM) │ socket(AF_INET, SOCK_DGRAM)
│ │
│ créer un datagramme avec l'@IP serveur │
│ et le port x, l'envoyer ─────────────────▶ lire le datagramme
│ │
│ lire le datagramme ◀───────────────────── écrire la réponse en précisant
│ │ l'@ et le port DU CLIENT
│ fermer clientSocket │
Le serveur UDP ne se ferme pas
Il n’y a aucune fermeture côté serveur dans le schéma : pas de connexion à fermer. Seul le client ferme son socket.
Client UDP
from socket import *
serverName = 'hostname'
serverPort = 12000
clientSocket = socket(AF_INET, SOCK_DGRAM)
message = input('Input lowercase sentence:')
clientSocket.sendto(message.encode(), (serverName, serverPort))
modifiedMessage, serverAddress = clientSocket.recvfrom(2048)
print(modifiedMessage.decode())
clientSocket.close()Serveur UDP
from socket import *
serverPort = 12000
serverSocket = socket(AF_INET, SOCK_DGRAM)
serverSocket.bind(('', serverPort))
print('The server is ready to receive')
while True:
message, clientAddress = serverSocket.recvfrom(2048)
modifiedMessage = message.decode().upper()
serverSocket.sendto(modifiedMessage.encode(), clientAddress)Lire le code UDP
SOCK_DGRAM= datagramme = UDP.sendto()/recvfrom()portent toujours une adresse : c’est la signature d’UDP.bind(('', serverPort)): le''signifie « toutes les interfaces » de la machine.clientAddressrécupéré parrecvfrom()est réinjecté danssendto()pour répondre.
Partie 3 — Sockets TCP
Le schéma d’échange
Client Serveur
│ créer un socket d'écoute sur le port x :
│ serverSocket = socket()
│ attendre une demande de connexion :
│ créer un socket et se connecter : │
│ socket(AF_INET, SOCK_STREAM) │
│ ═══════════ TCP Setup ══════════════════▶ connectionSocket = serverSocket.accept()
│ │
│ envoyer une requête ─────────────────────▶ lire la requête sur connectionSocket
│ │
│ lire la réponse ◀──────────────────────── écrire la réponse sur connectionSocket
│ │
│ fermer clientSocket │ fermer connectionSocket
Le point le plus important du TCP : DEUX sockets côté serveur
serverSocket— le socket d’accueil, qui écoute en permanence sur le port x les demandes de connexion.connectionSocket— créé paraccept(), dédié à un client, c’est lui qui porte l’échange.Le serveur peut ainsi continuer d’accepter de nouveaux clients pendant qu’il en sert un.
Client TCP
from socket import *
serverName = 'servername'
serverPort = 12000
clientSocket = socket(AF_INET, SOCK_STREAM)
clientSocket.connect((serverName, serverPort))
sentence = input('Input lowercase sentence:')
clientSocket.send(sentence.encode())
modifiedSentence = clientSocket.recv(1024)
print('From Server:', modifiedSentence.decode())
clientSocket.close()Serveur TCP
from socket import *
serverPort = 12000
serverSocket = socket(AF_INET, SOCK_STREAM)
serverSocket.bind(('', serverPort))
serverSocket.listen(1)
print('The server is ready to receive')
while True:
connectionSocket, addr = serverSocket.accept()
sentence = connectionSocket.recv(1024).decode()
capitalizedSentence = sentence.upper()
connectionSocket.send(capitalizedSentence.encode())
connectionSocket.close()Partie 4 — Comparaison des deux implémentations
| UDP | TCP | |
|---|---|---|
| Type de socket | SOCK_DGRAM | SOCK_STREAM |
| Connexion préalable | Aucune | connect() côté client, listen() + accept() côté serveur |
| Sockets côté serveur | 1 (serverSocket) | 2 (serverSocket + connectionSocket) |
| Envoi / réception | sendto() / recvfrom() — avec adresse | send() / recv() — sans adresse |
| Adresse du destinataire | Fournie à chaque message | Implicite, portée par la connexion |
| Fermeture côté serveur | Aucune | connectionSocket.close() |
La logique à retenir
Toute la différence de code découle d’un seul fait : TCP est orienté connexion. Comme la connexion mémorise qui parle à qui,
send()/recv()n’ont plus besoin d’adresse. UDP, sans connexion, doit transporter l’adresse dans chaque appel.
Les méthodes vues, par rôle
| Méthode | Protocole | Rôle |
|---|---|---|
socket(AF_INET, SOCK_DGRAM) | UDP | Créer un socket datagramme |
socket(AF_INET, SOCK_STREAM) | TCP | Créer un socket flux |
bind(('' , port)) | les deux (serveur) | Attacher le socket à un port local |
listen(n) | TCP (serveur) | Passer en écoute, file d’attente de n connexions |
accept() | TCP (serveur) | Accepter une connexion → retourne (connectionSocket, addr) |
connect((host, port)) | TCP (client) | Établir la connexion |
send() / recv(n) | TCP | Émettre / recevoir jusqu’à n octets |
sendto(data, addr) / recvfrom(n) | UDP | Émettre vers / recevoir depuis une adresse |
encode() / decode() | les deux | Convertir str ↔ bytes (la couche 6 en pratique !) |
close() | les deux | Fermer le socket |
Ne pas oublier
encode()/decode()Les sockets transportent des octets, pas des chaînes. C’est exactement le rôle de formatage de la couche présentation — cf. 2026-09-07 — Rôle de la couche Application.
⚠️ À retenir absolument (examen)
- Socket = abstraction de l’API entre couche application et couche transport.
- Une application réseau = des processus qui communiquent par messages.
SOCK_DGRAM= UDP ·SOCK_STREAM= TCP.- UDP : aucune connexion → l’IP et le port du destinataire sont dans chaque
sendto(). - UDP serveur : récupère l’adresse du client via
recvfrom()pour pouvoir répondre. - TCP serveur : deux sockets —
serverSocket(accueil,accept()) etconnectionSocket(dédié au client). - Séquence TCP serveur :
socket()→bind()→listen()→accept()→recv()/send()→close(). - Les données transitent en octets :
encode()à l’envoi,decode()à la réception.
❓ Points flous / à revoir
- Que fait exactement l’argument de
listen(1)— taille de la file d’attente ? - Pourquoi 2048 octets en UDP et 1024 en TCP dans les exemples ?
- Serveur TCP mono-client ici : comment gérer plusieurs clients simultanés (threads) ?
- Tester les 4 scripts en local (
serverName = 'localhost')
🔗 Liens
- Précédent : 2026-09-07 — Le protocole DNS
- Rappel TCP/UDP : 2026-09-04 — ARP et couche transport
- Révisions : Révisions — DNS et sockets
- Quiz : Quiz — DNS et sockets