Skip to content

Réseautage en Python

Python offre un support complet pour la programmation réseau, allant de l’accès aux sockets de bas niveau aux bibliothèques de haut niveau pour les protocoles d’application courants.

  • Accès de Bas Niveau : Le module socket fournit un accès à l’interface de socket BSD, permettant l’implémentation directe de clients et de serveurs utilisant les protocoles TCP (orienté connexion) et UDP (sans connexion).
  • Accès de Haut Niveau : Les bibliothèques standard offrent des abstractions pour des protocoles comme HTTP (http.client, urllib.request), FTP (ftplib), SMTP (smtplib), POP3 (poplib), IMAP (imaplib), etc. Des bibliothèques tierces comme requests simplifient davantage les interactions HTTP.

Ce chapitre se concentre sur les fondamentaux de la programmation de sockets de bas niveau à l’aide du module socket.

Les sockets sont les points d’extrémité d’un lien de communication bidirectionnel entre deux programmes exécutés sur un réseau. Un socket est lié à un numéro de port afin que la couche TCP puisse identifier l’application à laquelle les données sont destinées.

Les sockets facilitent la communication au sein d’un même processus, entre processus sur la même machine (en utilisant des sockets de domaine Unix ou de bouclage), ou entre processus sur différentes machines via Internet.

Terminologie Clé des Sockets :

TermeDescription
Domaine (ou Famille)Spécifie la famille de protocoles. Valeurs courantes :
AF_INET : Protocoles IPv4.
AF_INET6 : Protocoles IPv6.
AF_UNIX : Sockets de domaine Unix (pour la communication inter-processus locale).
TypeSpécifie la sémantique de communication. Valeurs courantes :
SOCK_STREAM : Flux orienté connexion, fiable (TCP).
SOCK_DGRAM : Datagrammes sans connexion, non fiables (UDP).
ProtocoleGénéralement 0, permettant au système de choisir le protocole approprié en fonction du domaine et du type (par exemple, IPPROTO_TCP pour SOCK_STREAM, IPPROTO_UDP pour SOCK_DGRAM).
Nom d’hôteIdentifie une interface réseau. Peut être un nom de domaine (par exemple, ‘www.example.com’), une chaîne d’adresse IPv4 (par exemple, ‘192.168.1.1’), une chaîne d’adresse IPv6, une chaîne vide ('') représentant INADDR_ANY (écoute sur toutes les interfaces disponibles), ou 'localhost' / '127.0.0.1' pour l’interface de bouclage.
PortUn nombre (0-65535) identifiant un processus ou un service spécifique sur un hôte. Les ports 0-1023 sont des ports bien connus nécessitant généralement des privilèges root/administrateur.

Le cœur de la programmation de sockets en Python est le module socket.

Utilisez socket.socket() pour créer un nouvel objet socket.

s = socket.socket(family=AF_INET, type=SOCK_STREAM, proto=0)

Paramètres courants :

  • family : Domaine du socket (par exemple, socket.AF_INET pour IPv4).
  • type : Type de socket (par exemple, socket.SOCK_STREAM pour TCP, socket.SOCK_DGRAM pour UDP).
  • proto : Numéro de protocole (généralement 0).

Utilisation de l’instruction with (Recommandé) :

Section titled “Utilisation de l’instruction with (Recommandé) :”

Les sockets doivent être fermés lorsqu’ils ne sont plus nécessaires. L’instruction with garantit que les sockets sont fermés automatiquement, de manière similaire à la gestion des fichiers.

import socket
try:
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
# Utiliser le socket 's' ici
print("Socket créé avec succès.")
# Le socket 's' sera fermé automatiquement à la sortie du bloc 'with'
except socket.error as err:
print(f"La création du socket a échoué avec l'erreur : {err}")
MéthodeDescription
s.bind((host, port))Lie le socket à une interface réseau spécifique (host) et un numéro de port.
s.listen(backlog)Permet au serveur d’accepter des connexions. backlog spécifie le nombre maximal de connexions en file d’attente.
s.accept()Attend une connexion client entrante. Renvoie un tuple (conn, addr) où conn est un nouvel objet socket pour la communication avec le client, et addr est le tuple d’adresse du client.
MéthodeDescription
s.connect((host, port))Connecte le socket client à un serveur à l’host et au port spécifiés.

Méthodes Générales des Sockets (TCP & UDP) :

Section titled “Méthodes Générales des Sockets (TCP & UDP) :”
MéthodeDescription
s.send(bytes)Transmet des données TCP. Les données doivent être de type bytes. Renvoie le nombre d’octets envoyés.
s.recv(bufsize)Reçoit des données TCP. bufsize est la quantité maximale de données (en octets) à recevoir en une seule fois. Renvoie les données reçues sous forme de bytes.
s.sendall(bytes)Transmet toutes les données de type bytes pour TCP. Gère les envois partiels potentiels.
s.sendto(bytes, address)Transmet un datagramme UDP (bytes) à l’adresse spécifiée sous forme de tuple (host, port).
s.recvfrom(bufsize)Reçoit un datagramme UDP. Renvoie un tuple (bytes, address) où bytes sont les données et address est l’adresse de l’expéditeur.
s.close()Ferme le socket. Géré automatiquement par l’instruction with.
socket.gethostname()Renvoie le nom d’hôte standard de la machine locale.

Important : En Python 3, les méthodes de socket send(), recv(), sendto() et recvfrom() opèrent sur des objets bytes, et non sur des chaînes de caractères. Vous devez encoder les chaînes en octets avant l’envoi et décoder les octets en chaînes après la réception.

Ce serveur écoute sur un port spécifique, accepte les connexions client, lit les données du client et renvoie les mêmes données (les renvoie en écho).

server.py
#!/usr/bin/env python3
import socket
HOST = '127.0.0.1' # Adresse d'interface de bouclage standard (localhost)
PORT = 65432 # Port d'écoute (les ports non privilégiés sont > 1023)
def run_server():
# Utiliser l'instruction 'with' pour la fermeture automatique du socket
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
try:
s.bind((HOST, PORT))
s.listen()
print(f"Serveur écoutant sur {HOST}:{PORT}")
# Attendre une connexion
conn, addr = s.accept() # Appel bloquant
# Utiliser 'with' aussi pour le socket de connexion client
with conn:
print(f"Connecté par {addr}")
while True:
# Recevoir des données (jusqu'à 1024 octets)
data = conn.recv(1024)
if not data:
# Si recv renvoie des octets vides, le client a fermé la connexion
print(f"Client {addr} déconnecté.")
break
# Décoder les octets reçus en chaîne de caractères pour l'affichage
print(f"Reçu de {addr} : {data.decode('utf-8')}")
# Renvoyer les données au client (encoder la chaîne en octets)
conn.sendall(data)
print(f"Renvoyé en écho à {addr}")
except socket.error as e:
print(f"Erreur de socket : {e}")
except KeyboardInterrupt:
print("\nArrêt du serveur.")
if __name__ == "__main__":
run_server()

Ce client se connecte au serveur, envoie un message et affiche la réponse renvoyée en écho.

client.py
#!/usr/bin/env python3
import socket
HOST = '127.0.0.1' # Nom d'hôte ou adresse IP du serveur
PORT = 65432 # Le port utilisé par le serveur
def run_client(message):
try:
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.connect((HOST, PORT))
print(f"Connecté au serveur {HOST}:{PORT}")
# Encoder le message en octets avant l'envoi
message_bytes = message.encode('utf-8')
s.sendall(message_bytes)
print(f"Envoyé : {message}")
# Recevoir les données renvoyées en écho
data = s.recv(1024)
# Décoder les octets reçus en chaîne de caractères
received_message = data.decode('utf-8')
print(f"Écho reçu : {received_message}")
except socket.error as e:
print(f"Erreur de socket : {e}")
except ConnectionRefusedError:
print(f"Connexion refusée. Le serveur est-il en cours d'exécution sur {HOST}:{PORT} ?")
if __name__ == "__main__":
message_to_send = "Hello, Server!"
run_client(message_to_send)
  1. Ouvrez un terminal et exécutez le serveur : python server.py
  2. Ouvrez un autre terminal et exécutez le client : python client.py

Sortie du Serveur :

Server listening on 127.0.0.1:65432
Connected by ('127.0.0.1', <client_port>)
Received from ('127.0.0.1', <client_port>): Hello, Server!
Echoed back to ('127.0.0.1', <client_port>)
Client ('127.0.0.1', <client_port>) disconnected.

Sortie du Client :

Connected to server 127.0.0.1:65432
Sent: Hello, Server!
Received echo: Hello, Server!

La bibliothèque standard de Python inclut des modules pour les protocoles Internet courants :

ProtocoleUsage PrincipalPort(s) Courant(s)Module(s) Python
HTTP/HTTPSAccès web80, 443urllib.request, http.client (Niveau inférieur). requests (Tiers, recommandé)
FTPTransfert de fichiers21ftplib
SMTPEnvoi d’e-mails25, 587, 465smtplib
POP3Récupération d’e-mails110, 995poplib
IMAP4Récupération d’e-mails143, 993imaplib
NNTPActualités Usenet119, 563nntplib
TelnetConnexion à distance23telnetlib
XML-RPCAppels de procédure à distanceVariablexmlrpc.client, xmlrpc.server

Pour les interactions web (HTTP/HTTPS), la bibliothèque tierce requests est largement utilisée et généralement préférée à urllib pour son API plus simple.

La programmation de sockets est un sujet vaste. Explorez ces ressources :