Study interactive :: Progress tools open in the Study Hub reader.

07. WebSockets

HTTP is request-response. The client asks, the server answers, the connection closes (or stays open for the next request). It works great for loading pages.

It works badly when the server needs to push something to the client. Chat messages, stock prices, live game state. The server can't just call the browser.

There are two ways to fake it with HTTP, and one real way to do it. The real way is WebSockets.

The fakes (and why they hurt)

Polling

The client asks every few seconds: "anything new?"

ServerClientServerClientwait about 3 secondswait about 3 secondsGET /messagesempty listGET /messagesempty listGET /messagesnew message

Simple. Wasteful. Latency capped at the polling interval. Bandwidth proportional to user count, not to messages.

Long polling

Smarter. The client asks, the server holds the connection open until it has something to say.

ServerClientServerClienthold up to about 30sGET /messagesnew messageGET /messages again

Better latency, fewer requests, but it's still HTTP. Every reply closes the connection and a new one opens.

Server-Sent Events (SSE)

Server can stream data over a single HTTP connection, but only in one direction (server to client). Good for live dashboards and notifications. Doesn't work for chat where the client also needs to send.

WebSockets: a real two-way pipe

A WebSocket starts as an HTTP request that says "actually, let's upgrade this to a different protocol":

GET /chat HTTP/1.1
Host: example.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
Sec-WebSocket-Version: 13

The server replies with 101:

HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=

After that the same TCP connection is no longer HTTP. It's a full-duplex pipe where either side can send small framed messages anytime.

persistent both waysClientServer

The connection stays open until someone closes it. Could be hours. Could be days.

When to use WebSockets

When not to use them:

Code: chat in the browser

JavaScript side:

const ws = new WebSocket("wss://example.com/chat");

ws.onopen = () => {
  console.log("connected");
  ws.send(JSON.stringify({ type: "hello", name: "Ada" }));
};

ws.onmessage = (event) => {
  const msg = JSON.parse(event.data);
  console.log("got:", msg);
};

ws.onclose = () => console.log("disconnected");

Server side in Python with websockets:

import asyncio, json
import websockets

clients = set()

async def handler(ws):
    clients.add(ws)
    try:
        async for raw in ws:
            msg = json.loads(raw)
            # broadcast to everyone else
            for client in clients:
                if client is not ws:
                    await client.send(json.dumps(msg))
    finally:
        clients.remove(ws)

async def main():
    async with websockets.serve(handler, "0.0.0.0", 8000):
        await asyncio.Future()  # run forever

asyncio.run(main())

That's a working broadcast chat in 15 lines.

Scaling WebSockets (the hard part)

This is where WebSockets get interesting. One server can hold maybe 50,000 to 500,000 open connections (depends on tuning, OS limits, memory). After that, you need to shard across many servers.

Problem: if Alice is connected to server A and Bob is on server B, how does Alice's message reach Bob?

WebSocketWebSocketneed a fan-out pathAliceServer ABobServer B

You can't just put a load balancer in front and call it done. The servers need a way to talk to each other.

The standard answer: a pub/sub layer in the middle. Redis pub/sub is the common starter pick. Each WebSocket server subscribes to channels. When server A receives a message for room "x", it publishes to channel "x". Server B is listening to "x" and forwards to its connected users.

publish room xsubscribe room xAliceServer APub/sub e.g. RedisServer BBob

At very large scale you replace Redis with Kafka, RabbitMQ, or NATS. We'll come back to message queues in Chapter 19.

Watch out for

Alternatives worth knowing

Things to remember

Going deeper