Le protocole WebSocket permet d'établir un canal de communication bidirectionnel et persistant sur une seule connexion TCP. Contrairement au modèle HTTP classique basé sur des requêtes-réponses, les WebSockets autorisent le serveur à pousser des données vers le client de manière proactive, ce qui est idéal pour les applications temps réel.
Caractéritsiques principales du protocole
- Communication Full-Duplex : Échange simultané de données entre l'émetteur et le récepteur.
- Persistance : Une fois la poignée de main (handshake) effectuée, la connexion reste ouverte.
- Légèreté : Réduction de l'en-tête des messages par rapport à HTTP, minimisant la latence globale.
Sélection d'une bibliothèque Python
Plusieurs options s'offrent aux développeurs Python pour interagir avec des serveurs WebSocket :
websockets: Une bibliothèque moderne construite surasyncio, privilégiée pour sa simplicité et ses performances.websocket-client: Une implémentation synchrone plus traditionnelle.autobahn: Un framework complet supportant WebSocket et WAMP.
L'installation de la bibliothèque recommandée se fait via pip :
pip install websockets
Implémentation d'un client asynchrone de base
L'exemple suivant utilise la syntaxe async/await pour établir une connexion, transmettre une chaîne de caractères et traiter la réponse du serveur.
import asyncio
import websockets
async def demarrer_client_ws():
url_serveur = "ws://localhost:8000"
async with websockets.connect(url_serveur) as session:
print(f"Connexion établie avec {url_serveur}")
# Envoi d'une charge utile
donnees_sortantes = "Action: Ping"
await session.send(donnees_sortantes)
print(f"Envoi : {donnees_sortantes}")
# Attente de la réponse
reponse = await session.recv()
print(f"Réponse reçue : {reponse}")
if __name__ == "__main__":
asyncio.run(demarrer_client_ws())
Cas d'utilisation : Messagerie interactive
Dans ce scénario, le client maintient une boucle active pour permettre l'envoi continu de messages utilisateur tout en écoutant les retours du serveur.
import asyncio
import websockets
async def flux_messagerie():
cible = "ws://localhost:8000/chat"
try:
async with websockets.connect(cible) as ws:
print("Session de chat active. Tapez 'exit' pour quitter.")
while True:
texte = input("Votre message > ")
if texte.lower() == 'exit':
break
await ws.send(texte)
echo = await ws.recv()
print(f"[Serveur] : {echo}")
except websockets.exceptions.ConnectionClosed:
print("La connexion a été interrompue.")
asyncio.run(flux_messagerie())
Cas d'utilisation : Réception de données boursières
Ce modèle se concentre sur la consommation d'un flux de données descendant (streaming) où le client traite les mises à jour envoyées par le serveur de manière asynchrone.
import asyncio
import websockets
import json
async def monitoring_marche():
uri_api = "wss://api.bourse-exemple.com/ticks"
async with websockets.connect(uri_api) as flux:
print("Abonnement au flux boursier...")
while True:
try:
raw_data = await flux.recv()
data_parsed = json.loads(raw_data)
symbole = data_parsed.get("symbol")
prix = data_parsed.get("price")
print(f"Mise à jour : {symbole} -> {prix} USD")
except Exception as e:
print(f"Erreur de flux : {e}")
break
asyncio.run(monitoring_marche())
Cas d'utilisation : Visualisation de métriques en temps réel
L'intégration avec des bibliothèques de visualisation comme Matplotlib permet de transformer les flux WebSocket en graphiques dynamiques.
import asyncio
import websockets
import matplotlib.pyplot as plt
# Configuration de l'affichage dynamique
plt.style.use('ggplot')
valeurs_y = []
indices_x = []
async def recuperer_et_tracer():
endpoint = "ws://votre-serveur-metriques.io/stats"
async with websockets.connect(endpoint) as canal:
plt.ion()
fig, axe = plt.subplots()
courbe, = axe.plot(indices_x, valeurs_y, color='green')
while True:
msg = await canal.recv()
nombre = float(msg)
valeurs_y.append(nombre)
indices_x.append(len(valeurs_y))
# Limitation de la fenêtre d'affichage (20 derniers points)
if len(valeurs_y) > 20:
indices_x.pop(0)
valeurs_y.pop(0)
courbe.set_xdata(range(len(valeurs_y)))
courbe.set_ydata(valeurs_y)
axe.relim()
axe.autoscale_view()
plt.pause(0.1)
plt.draw()
asyncio.run(recuperer_et_tracer())
Le choix d'une architecture asynchrone via asyncio est crucial pour les clients WebSocket, car il permet de gérer efficacement les entrées/sorties sans bloquer l'exécution globale du programme, notamment lors de l'attente de paquets réseau.