Project Oxygen & Ideo-LabIDEO LAB Dashboard 2026
MASTERCLASS 2025

🔌 Architecture WebSockets

Implémentation Full-Duplex asynchrone avec Django Channels & Redis.

01

Introduction WS

Introduction : GenÚse et Rupture Technologique du Temps Réel.

TCP/IP RFC 6455 Upgrade Header
01

Le Protocole WS

Différences avec HTTP, cycle de vie du Handshake et état de persistance TCP.

TCP/IP RFC 6455 Upgrade Header
02

Installation & Stack

Configuration de l'environnement virtuel, Channels, Daphne et le serveur Redis.

ASGI Redis Stack Daphne
03

Routing & Config

Définition de l'application ASGI, protocol_type_router et intégration settings.py.

asgi.py Channel Layers
04

Consumers (Backend)

Logique asynchrone : Connect, Receive, Disconnect et Broadcasting.

AsyncConsumer JsonWebsocket
05

Frontend (Javascript)

Gestion de la connexion native, reconnexion automatique et parsing JSON.

Event Listeners ReconnectingWS
06

Déploiement Pro

Nginx en Reverse Proxy, SSL (WSS), Superviseur et Sticky Sessions.

Nginx Upstream WSS SSL Gunicorn/Uvicorn
0.0 Introduction : GenÚse et Rupture Technologique du Temps Réel
L'héritage HTTP/1.1 : Le mur du Stateless

Le web a été conçu sur le modÚle Request-Response. Dans ce monde, le serveur est "sourd" et "amnésique" : il ne peut pas initier de contact avec le client. Pour simuler du temps réel, nous utilisions des "hacks" coûteux :

  • Short Polling : RequĂȘtes rĂ©pĂ©tĂ©es (ex: toutes les 1s). RĂ©sultat : 90% de requĂȘtes vides et une saturation inutile de la bande passante.
  • Long Polling (Comet) : Le serveur suspend la rĂ©ponse. ProblĂšme : Consomme un thread/processus par utilisateur, provoquant l'effondrement des serveurs sous charge.
  • SSE (Server-Sent Events) : Unidirectionnel seulement.
Visualisation du Flux Inefficient (HTTP)
                            Client -> [SYN] -> Server
                            Client -> [GET + 800 bytes Headers] -> Server
                            Server -> [200 OK + 20 bytes Data] -> Client
                            Server -> [FIN/CLOSE] -> Client (Connexion détruite)
                            -- Répéter 1000 fois par minute --
                        

Verdict : 98% de métadonnées pour 2% de données utiles.

WebSocket (RFC 6455) : L'unification des flux

WebSocket n'est pas une "couche au-dessus" de HTTP, c'est un protocole indépendant qui utilise le port 80/443 pour traverser les firewalls. Il transforme une transaction HTTP éphémÚre en un tunnel TCP permanent.

// Anatomie d'une Trame (Frame) WS [FIN (1bit)][OpCode (4bit)][Mask (1bit)][Payload Len (7bit)][Payload Data...]

L'overhead d'un message WebSocket n'est que de 2 Ă  14 octets, contre plusieurs Ko pour HTTP.

Le Handshake (La Poignée de main) :
  1. Client envoie Upgrade: websocket
  2. Serveur génÚre une clé Sec-WebSocket-Accept via SHA-1
  3. Le socket TCP est "détourné" du flux HTTP classique
CaractéristiqueHTTP / RESTWebSocket
ModĂšlePull (Client demande)Push/Pull (Bidirectionnel)
État (State)Stateless (IndĂ©pendant)Stateful (Contexte conservĂ©)
HeadersMassifs (Cookies, User-Agent...)Négligeables (Framing minimal)
LatenceÉlevĂ©e (RTT + Handshake TCP/TLS)Ultra-basse (Tube dĂ©jĂ  ouvert)
ScalabilitéFacile (Horizontale/Stateless)Complexe (Gestion des sessions actives)
Quand l'utiliser impérativement ?
  • Collaboratif : Curseurs en temps rĂ©el, Ă©dition simultanĂ©e.
  • Finance : Flux de prix (OrderBooks) oĂč 50ms font la diffĂ©rence.
  • Monitoring : Dashboards Ops / Logs serveurs en streaming.
Les contraintes de l'indispensable

Le passage au WebSocket impose une réarchitecture complÚte du backend :
- Fin du synchrone (nécessite l'Asynchrone/Event Loop).
- Gestion des "Zombie Connections" et des Timeouts.
- Besoin d'un Message Broker (Redis) pour synchroniser plusieurs serveurs.

🎯 Conclusion : WebSocket est l'outil ultime pour passer d'un web de "consultation" à un web "interactif vivant".

Théorie & Handshake
Le paradigme "Event-Driven"

Contrairement au HTTP (Request/Response), le WebSocket est un tube ouvert :

  • Persistance : Pas besoin de renvoyer les headers HTTP Ă  chaque message.
  • Low Latency : IdĂ©al pour le trading, le chat ou le gaming.
  • Full Duplex : Le serveur peut "pousser" (push) une info sans demande du client.
Flux du Handshake
Client -> HTTP GET (Upgrade: websocket) Server -> 101 Switching Protocols [ Canal Ouvert - Frames Binaires/Texte ]
Pourquoi Channels ?

Django est nativement synchrone. Channels permet d'encapsuler Django dans une couche asynchrone (ASGI) qui gĂšre les connexions longues pendant que Django continue de traiter ses vues classiques.

Installation de la Stack

Installez les composants essentiels pour un environnement asynchrone performant.

# 1. Framework Channels pip install channels==4.0.0 # 2. Support Redis (obligatoire pour le broadcast) pip install channels-redis # 3. Serveur ASGI pip install daphne uvicorn # 4. Export vers requirements.txt pip freeze > requirements.txt

Redis sert de "HUB". Sans lui, un utilisateur sur le Worker A ne peut pas parler Ă  un utilisateur sur le Worker B.

# Via Docker (Recommandé) docker run -p 6379:6379 -d redis:7-alpine # Test de connexion redis-cli ping -> PONG
Consumer Asynchrone (Chat avancé)

Voici l'implémentation d'un Consumer qui gÚre des groupes (Rooms) de maniÚre robuste.

# chat/consumers.py import json from channels.generic.websocket import AsyncWebsocketConsumer class SuperChatConsumer(AsyncWebsocketConsumer): async def connect(self): self.room_name = self.scope['url_route']['kwargs']['room_id'] self.room_group_name = f'chat_{self.room_name}' # Authentification simple via scope if self.scope["user"].is_anonymous: await self.close() else: # Rejoindre le groupe de diffusion await self.channel_layer.group_add(self.room_group_name, self.channel_name) await self.accept() async def disconnect(self, close_code): # Quitter le groupe proprement await self.channel_layer.group_discard(self.room_group_name, self.channel_name) async def receive(self, text_data): # Réception message du Client data = json.loads(text_data) message = data['message'] # Envoi au groupe (Broadcast) await self.channel_layer.group_send( self.room_group_name, { 'type': 'chat_message', 'message': message, 'sender': self.scope["user"].username } ) async def chat_message(self, event): # Cette méthode est appelée pour chaque membre du groupe await self.send(text_data=json.dumps({ 'message': event['message'], 'sender': event['sender'] }))
Frontend Implementation
Script Client Natif
const roomName = "lab-01"; const wsScheme = window.location.protocol === "https:" ? "wss" : "ws"; const chatSocket = new WebSocket( `${wsScheme}://${window.location.host}/ws/chat/${roomName}/` ); chatSocket.onmessage = function(e) { const data = json.parse(e.data); console.log("Message reçu:", data.message); appendMessageToUI(data); }; chatSocket.onclose = function(e) { console.error('Socket fermé. Tentative de reconnexion...'); setTimeout(reconnect, 2000); }; function sendMessage(msg) { chatSocket.send(JSON.stringify({'message': msg})); }
Reconnexion : Le WebSocket natif ne se reconnecte pas tout seul. Utilisez une boucle `setTimeout` ou la lib `reconnecting-websocket`.
Sécurité Origin

Par défaut, Django Channels vérifie l'Origin. Si vous utilisez un domaine différent, configurez AllowedHostsOriginValidator.

Diagnostics WebSockets