Skip to content
networking protocols

WebSocket

websocket real-time protocols http bidirectional
Plain English

Normal HTTP is like sending letters: your browser mails a question, the server mails back an answer, and the conversation ends. WebSocket is like a phone call: you connect once and both sides can speak at any moment without waiting for the other to ask first. This is why chat messages appear instantly, live scoreboards update in real time, and your collaborative document shows other people’s cursors moving.

Technical Definition

WebSocket, defined in RFC 6455, provides a persistent, full-duplex communication channel over a single TCP connection. It starts as an HTTP/1.1 request and upgrades to the WebSocket protocol, bypassing the request-response model entirely.

Handshake (HTTP Upgrade):

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

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

The Sec-WebSocket-Accept is the SHA-1 of the client key concatenated with a fixed GUID (RFC 6455 section 1.3), preventing cache poisoning by non-WebSocket intermediaries.

Frame structure: After the handshake, both sides communicate in lightweight frames (not HTTP). Each frame has:

  • FIN bit (last frame in a message)
  • Opcode: 0x1 text, 0x2 binary, 0x8 close, 0x9 ping, 0xA pong
  • Payload length (7, 23, or 71 bits depending on size)
  • Masking key (client-to-server frames are masked; server-to-client are not)

WebSocket vs. alternatives:

FeatureWebSocketServer-Sent Events (SSE)HTTP long-polling
DirectionBidirectionalServer-to-client onlyServer-to-client
ProtocolCustom over TCPHTTP/1.1 or HTTP/2HTTP
ConnectionPersistentPersistentRepeated reconnect
Browser supportUniversalUniversal (IE11 needs polyfill)Universal
Best forChat, games, collabLive feeds, notificationsLegacy fallback

wss:// (WebSocket Secure): WebSocket over TLS, analogous to HTTPS. Required in production. Shares the same TLS handshake as HTTPS; same certificates apply.

Keepalive: TCP keepalives may not traverse all load balancers and proxies. The WebSocket protocol includes Ping/Pong frames for application-level keepalives. Clients or servers send a Ping; the other side must respond with a matching Pong.

WebSocket server and client implementation

// Node.js WebSocket server (using the 'ws' library)
import { WebSocketServer, WebSocket } from "ws";

const wss = new WebSocketServer({ port: 8080 });

wss.on("connection", (ws, req) => {
  const clientIp = req.socket.remoteAddress;
  console.log(`Client connected: ${clientIp}`);

  // Send a welcome message
  ws.send(JSON.stringify({ type: "welcome", message: "Connected" }));

  ws.on("message", (rawData) => {
    const message = JSON.parse(rawData.toString()) as { type: string; text: string };

    // Broadcast to all connected clients
    wss.clients.forEach((client) => {
      if (client.readyState === WebSocket.OPEN) {
        client.send(JSON.stringify({ type: "message", text: message.text }));
      }
    });
  });

  // Keepalive ping every 30 seconds
  const pingInterval = setInterval(() => {
    if (ws.readyState === WebSocket.OPEN) ws.ping();
  }, 30_000);

  ws.on("close", () => {
    clearInterval(pingInterval);
    console.log(`Client disconnected: ${clientIp}`);
  });
});
// Browser WebSocket client with reconnection
function createConnection(url) {
  const ws = new WebSocket(url);

  ws.addEventListener("open", () => {
    console.log("Connected");
    ws.send(JSON.stringify({ type: "hello" }));
  });

  ws.addEventListener("message", (event) => {
    const data = JSON.parse(event.data);
    console.log("Received:", data);
  });

  ws.addEventListener("close", (event) => {
    console.log(`Disconnected (code ${event.code}). Reconnecting in 3s...`);
    setTimeout(() => createConnection(url), 3000);
  });

  return ws;
}

const socket = createConnection("wss://example.com/ws");
In the Wild

WebSocket powers Slack, Figma, GitHub Codespaces, multiplayer games, trading terminals, and live sports scoreboards. The most common production issue is WebSocket connections dropping behind load balancers: AWS ALB requires explicit WebSocket support enabled, and sticky sessions (session affinity) must be configured so reconnecting clients hit the same backend instance. Nginx proxies WebSocket with proxy_http_version 1.1, proxy_set_header Upgrade $http_upgrade, and proxy_set_header Connection "upgrade". At scale, stateful WebSocket connections are a problem: a single server can hold hundreds of thousands of connections, but horizontal scaling requires a shared pub/sub backend (Redis Pub/Sub, Kafka) so messages from one user reach all instances. Libraries like Socket.IO abstract over WebSocket and provide automatic fallback to long-polling for environments that block WebSocket.