HTTP is a request-response protocol — the client sends a request, the server responds, the connection closes (or is reused for the next request). For real-time applications that need the server to push data to the client without a client request (chat messages, live notifications, dashboards updating as data changes), HTTP polling (repeated requests) wastes bandwidth and adds latency. The WebSocket protocol solves this by upgrading an HTTP connection to a persistent, full-duplex (bidirectional) TCP channel — the server can push messages to the client at any time, and the client can send messages to the server simultaneously.
WebSocket vs HTTP vs SSE
| Feature | HTTP Polling | Server-Sent Events | WebSockets |
|---|---|---|---|
| Direction | Client → Server → Client | Server → Client only | Full duplex (both) |
| Protocol | HTTP | HTTP | WebSocket (ws:// wss://) |
| Browser reconnect | Manual | Automatic (built-in) | Manual |
| Proxy support | Full | Full | Some proxies require config |
| Overhead per message | High (full HTTP headers) | Low | Very low (2–10 bytes) |
| Best for | Infrequent updates, simple setup | Live feeds, progress bars | Chat, collaborative editing, gaming |
Upgrade: websocket header. The server responds with 101 Switching Protocols, and the connection is transformed into a WebSocket channel that persists until either side closes it. Because the handshake is HTTP, WebSockets can reuse the same port (80/443), work through most firewalls, and support standard HTTP authentication headers during the upgrade phase.WebSocket Connection Lifecycle
1. CONNECT — Client initiates HTTP upgrade request
Client → Server: GET /ws HTTP/1.1
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
2. HANDSHAKE — Server accepts and upgrades
Server → Client: HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=
3. COMMUNICATE — Full-duplex bidirectional messages
Client ← → Server: text / binary / ping / pong frames
4. CLOSE — Either side can initiate close
One side sends: Close frame (opcode 0x8, optional status code + reason)
Other side responds: Close frame
TCP connection closes
Common close status codes:
1000 — Normal closure (intentional)
1001 — Going away (server shutdown, page navigation)
1006 — Abnormal closure (connection lost without close frame)
1008 — Policy violation
1011 — Server error
Use Case Decision Guide
| Use Case | Recommended | Why |
|---|---|---|
| Live chat | WebSocket | Bidirectional, low latency |
| Collaborative document editing | WebSocket | Real-time bidirectional changes |
| Live notifications | SSE | Server-push only, simpler, auto-reconnect |
| Live dashboard metrics | SSE | Server-push, regular intervals |
| Export progress bar | SSE | One-way progress stream |
| Online multiplayer game | WebSocket | High-frequency bidirectional updates |
| Live cursor positions | WebSocket | Client sends position, server broadcasts |
| Order status updates | SSE or polling | Infrequent server-push, no client input |
Common Mistakes
Mistake 1 — Using WebSockets when SSE or polling is sufficient
❌ Wrong — using WebSocket for a one-way notification feed:
# Complex bidirectional WebSocket just to push notifications to browser
# SSE is simpler, works through all proxies, auto-reconnects
✅ Consider — SSE for server-to-client only streaming (covered in Lesson 5).
Mistake 2 — Not handling connection close gracefully
❌ Wrong — ignoring WebSocketDisconnect:
@app.websocket("/ws")
async def ws(websocket: WebSocket):
await websocket.accept()
while True:
msg = await websocket.receive_text()
# If client disconnects: raises WebSocketDisconnect — uncaught exception!
✅ Correct — always catch WebSocketDisconnect in the message loop.
Mistake 3 — Storing all connections in a global dict without cleanup
❌ Wrong — memory leak from disconnected clients staying in the dict:
connections[user_id] = websocket
# Never removed on disconnect → dict grows unbounded
✅ Correct — remove from storage in the disconnect handler or finally block.
Quick Reference
| Concept | Details |
|---|---|
| Protocol | ws:// (plain) or wss:// (TLS, required in production) |
| Upgrade header | HTTP → WebSocket via Upgrade: websocket |
| Status 101 | Switching Protocols — handshake accepted |
| Full duplex | Both sides can send independently at any time |
| Disconnect code 1000 | Normal closure |
| Disconnect code 1006 | Abnormal — connection lost (detect stale connections) |