WebSocket Fundamentals — Protocol, Lifecycle and Use Cases

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
Note: The WebSocket handshake begins with a standard HTTP request that includes an 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.
Tip: Choose the right technology for your use case. For live notifications where the server pushes updates to users (new comment on your post, follow notification), Server-Sent Events are simpler — they use plain HTTP, handle reconnects automatically in browsers, and work through all HTTP proxies. Use WebSockets when you need bidirectional communication (chat, collaborative editing, live cursors) or very high-frequency updates (gaming, live trading). In FastAPI, both are well-supported.
Warning: Each WebSocket connection is a persistent TCP connection that consumes server resources (memory, file descriptor). A server with 1,000 concurrent WebSocket connections holds 1,000 open connections simultaneously — very different from 1,000 HTTP requests per second (which complete and release resources). Plan your infrastructure accordingly: WebSocket servers typically need connection limits, heartbeat mechanisms to detect stale connections, and horizontal scaling via a pub/sub broker (Redis) to route messages across multiple server processes.

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)

🧠 Test Yourself

You need to push live post view count updates to all visitors of a post’s page. Visitors do not send any data to the server. Which technology is most appropriate?