Understanding WebSockets

The HTTP Upgrade handshake (101), Sec-WebSocket-Key/Accept, frames, ws:// vs wss://, WebSocket vs SSE vs long-polling, subprotocols, and scaling.

WebSocket is a full-duplex protocol that lets the client and server exchange messages in both directions at any time over a single TCP connection. Unlike HTTP, whose unit is a request/response pair, once the connection is up the server can push data without the client asking first — ideal for chat, live notifications, collaborative editing, and games.

The HTTP Upgrade handshake (101)

Surprisingly, a WebSocket connection starts as an ordinary HTTP request. The client asks to switch protocols with an Upgrade: websocket header; if the server agrees, it responds with 101 Switching Protocols, and from that point the same TCP connection leaves HTTP behind and becomes a channel for WebSocket frames.

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

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

Sec-WebSocket-Key and Accept

The handshake's Sec-WebSocket-Key is not a security token — it's a value to confirm the responder really is a server that understands WebSocket. The server appends the fixed GUID 258EAFA5-E914-47DA-95CA-C5AB0DC85B11 to the client's key, takes the SHA-1 hash, Base64-encodes it, and returns it as Sec-WebSocket-Accept. When the client does the same computation and the values match, it's assured it reached a genuine WebSocket server, not some HTTP server that answered by accident.

Frames

After the handshake, data flows not as HTTP but as lightweight frames. Each frame has an opcode distinguishing text (0x1), binary (0x2), close (0x8), ping (0x9), and pong (0xA). A large message can be split across frames, with the FIN bit marking the last piece. Client-to-server frames must be masked, a rule that prevents attacks where an intermediary proxy mistakes the traffic for HTTP and poisons a cache.

ws:// vs wss://

There are two URL schemes: ws:// is cleartext, and wss:// is WebSocket over TLS. It mirrors HTTP vs HTTPS, and in practice you should always use wss:// to avoid eavesdropping, proxy interference, and mixed-content problems. Attempting ws:// from an HTTPS page is blocked as mixed content.

WebSocket vs SSE vs long-polling

There are several ways to do real-time, and the choice follows your requirements.

Subprotocols and scaling

WebSocket defines only how frames are transported, not what the messages inside mean. Applications negotiate a subprotocol (e.g., graphql-ws, MQTT-over-WS) via the Sec-WebSocket-Protocol header to agree on message format. Scaling is tricky: a WebSocket is a long-lived, stateful connection, so you can't route it to any server like stateless HTTP. Spreading across servers needs sticky sessions at the load balancer plus a pub/sub backplane (e.g., Redis) to fan messages out between servers. At high connection counts you must also manage file-descriptor and memory limits.