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 :

  1. Le client lit une ligne saisie au clavier.
  2. Il envoie ces données au serveur.
  3. Le serveur reçoit les données.
  4. Le serveur transforme les caractères en majuscules.
  5. Il renvoie la traduction au client.
  6. 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.
  • clientAddress récupéré par recvfrom() est réinjecté dans sendto() 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éé par accept(), 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

UDPTCP
Type de socketSOCK_DGRAMSOCK_STREAM
Connexion préalableAucuneconnect() côté client, listen() + accept() côté serveur
Sockets côté serveur1 (serverSocket)2 (serverSocket + connectionSocket)
Envoi / réceptionsendto() / recvfrom() — avec adressesend() / recv() — sans adresse
Adresse du destinataireFournie à chaque messageImplicite, portée par la connexion
Fermeture côté serveurAucuneconnectionSocket.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éthodeProtocoleRôle
socket(AF_INET, SOCK_DGRAM)UDPCréer un socket datagramme
socket(AF_INET, SOCK_STREAM)TCPCré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 deuxConvertir str ↔ bytes (la couche 6 en pratique !)
close()les deuxFermer 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()) et connectionSocket (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