How WebSockets Work — Persistent Connections and Real-Time Data

How WebSockets Work — Persistent Connections and Real-Time Data

2026-03-24

WebSockets provide full-duplex communication over a single TCP connection. Unlike HTTP, which is request-response (client asks, server answers, connection idles), a WebSocket stays open and either side can send messages at any time without waiting for the other.

This makes WebSockets the standard protocol for real-time applications — chat, live dashboards, multiplayer games, collaborative editing, stock tickers, and anything where the server needs to push data to the client the instant it's available.

The HTTP Upgrade Handshake

A WebSocket connection starts as a normal HTTP request. The client sends an Upgrade header asking the server to switch protocols:

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

The server agrees by responding with 101 Switching Protocols:

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

The Sec-WebSocket-Accept value is derived from the client's key using SHA-1 and a fixed GUID — this proves the server understands the WebSocket protocol and isn't just echoing headers.

After the 101 response, the TCP connection is no longer HTTP. Both sides speak the WebSocket frame protocol until one side sends a close frame or the connection drops.

Full-Duplex Communication

HTTP is half-duplex: the client sends a complete request, then waits for a complete response. Even with HTTP/2 multiplexing, the server can only respond to requests — it cannot push data unprompted (server push in HTTP/2 was removed from most browsers).

WebSockets are full-duplex: both sides can send messages simultaneously on the same connection. The server can push a notification to the client while the client is sending a chat message. No polling. No waiting. No wasted round trips.

HTTP upgrade → persistent bidirectional frames

Client Server

HTTP upgrade handshake

GET /chat Upgrade: websocket 101 Switching Protocols WebSocket frames (bidirectional) text: "hello" text: "world" text: "new message from Bob" ping pong close: 1000 (normal) close: 1000 (ack)

Frame Types

After the handshake, data is sent as frames. Each frame has an opcode that identifies its type:

OpcodeTypePurpose
0x1TextUTF-8 text data (JSON, plain text)
0x2BinaryRaw bytes (protobuf, images, compressed data)
0x8CloseInitiate connection close (includes status code)
0x9PingHeartbeat — "are you still there?"
0xAPongHeartbeat response — "yes, I'm here"

Text frames are the most common in web applications (JSON messages). Binary frames are used when performance matters or the data isn't text. Large messages can be split across multiple frames using the FIN bit — intermediate frames have FIN=0, the final frame has FIN=1.

Frames are lightweight. A small text message has only 2-6 bytes of overhead (opcode + payload length), compared to hundreds of bytes of HTTP headers per request.

Connection Management

WebSocket connections are long-lived, which introduces challenges that short-lived HTTP requests don't have.

Heartbeats. Networks drop idle connections. Load balancers, proxies, and firewalls time out connections that send no data. Ping/pong frames keep the connection alive. The server sends a ping every 30-60 seconds; the client responds with a pong. If a pong doesn't arrive, the connection is considered dead.

Reconnection. Connections drop — network changes, server deploys, load balancer rotations. Clients must implement automatic reconnection with exponential backoff. On reconnect, the client needs to re-authenticate and re-subscribe to any channels or topics. The server should not assume a reconnected client has any prior state.

Scaling. Each WebSocket connection holds a TCP socket open on the server. A REST API handles 10,000 requests per second on a few connections (keep-alive + pipelining). A WebSocket server with 10,000 connected users holds 10,000 open sockets simultaneously. This requires event-driven servers (not thread-per-connection) and careful memory management.

Authentication. The WebSocket handshake is a standard HTTP request, so cookies and headers work normally during the upgrade. After the upgrade, there's no standard way to refresh authentication mid-connection. Common approaches: send an auth message as the first frame, or close and reconnect when the token expires.

WebSockets vs SSE vs Polling

WebSocketSSE (Server-Sent Events)Long PollingShort Polling
DirectionBidirectionalServer → client onlyServer → client onlyServer → client only
ProtocolWS (custom framing)HTTP (text/event-stream)HTTPHTTP
ConnectionPersistentPersistentHeld open until data arrivesNew request each interval
Browser supportAll modern browsersAll modern (except IE)UniversalUniversal
Proxy/CDN supportRequires ws:// supportWorks with any HTTP proxyWorks everywhereWorks everywhere
Overhead per message2-6 bytes~50 bytes (HTTP chunked)Full HTTP headersFull HTTP headers
Best forChat, games, collab editingNotifications, live feedsLegacy compatSimple, low-frequency updates

Use WebSockets when both client and server send messages frequently. Chat, multiplayer games, collaborative editing.

Use SSE when only the server pushes data. Live dashboards, notification feeds, log tailing. SSE is simpler — it's just HTTP, works through proxies, and automatically reconnects.

Use polling when real-time isn't critical and simplicity matters. Check for updates every 30 seconds. The overhead is acceptable for low-frequency data.

Security

WebSocket connections use ws:// (unencrypted) or wss:// (encrypted with TLS). Always use wss:// in production — the same way you always use https://.

The upgrade handshake includes an Origin header, which the server should validate to prevent cross-site WebSocket hijacking. This is the WebSocket equivalent of CORS for HTTP.

Next Steps