Menu
Course/Networking & Communication/WebSockets & Server-Sent Events

WebSockets & Server-Sent Events

Real-time communication protocols: WebSocket full-duplex connections vs SSE one-way streams, connection management, and scaling challenges.

12 min readHigh interview weight

Why Real-Time?

HTTP's request-response model requires the client to initiate every interaction. For applications that need to push data to clients — chat messages, live scores, collaborative editing, stock tickers, order status updates — a mechanism that allows the server to send data without a prior client request is essential.

WebSockets

WebSocket is a protocol (RFC 6455) that upgrades an HTTP connection into a full-duplex, persistent, bidirectional channel. Either the client or the server can send messages at any time without the overhead of HTTP headers on each exchange.

Loading diagram...
WebSocket handshake upgrades HTTP, then both sides can send messages freely
javascript
// Client-side WebSocket
const ws = new WebSocket('wss://chat.example.com/room/42');

ws.onopen = () => {
  ws.send(JSON.stringify({ type: 'join', userId: '123' }));
};

ws.onmessage = (event) => {
  const msg = JSON.parse(event.data);
  renderMessage(msg);
};

ws.onerror = (error) => console.error('WebSocket error:', error);
ws.onclose = (event) => {
  console.log('Disconnected. Code:', event.code);
  // Reconnect with exponential backoff
};
  • Full duplex: Both client and server can send messages independently, simultaneously.
  • Low overhead: After the handshake, messages have only 2-14 bytes of framing overhead vs. ~800 bytes of HTTP headers.
  • Persistent connection: No handshake cost per message (unlike HTTP/1.1 polling).
  • Binary support: Can send binary frames (ArrayBuffer), not just text — useful for game state, images, or audio.

Server-Sent Events (SSE)

Server-Sent Events is a simpler protocol built on plain HTTP. The server opens a long-lived HTTP response and streams text events to the client. The client can only receive data (one-way), but it gets automatic reconnection and event ID tracking for free via the browser's `EventSource` API.

javascript
// Client: EventSource handles reconnection automatically
const evtSource = new EventSource('/api/stream/orders');

evtSource.addEventListener('order_update', (event) => {
  const update = JSON.parse(event.data);
  updateOrderStatus(update);
});

evtSource.onerror = () => {
  // EventSource auto-reconnects after a delay
  console.log('Connection lost, reconnecting...');
};
text
# SSE response format (plain text)
HTTP/1.1 200 OK
Content-Type: text/event-stream
Cache-Control: no-cache

id: 1
event: order_update
data: {"orderId": "ABC", "status": "shipped"}

id: 2
event: order_update
data: {"orderId": "XYZ", "status": "delivered"}

: heartbeat comment (keeps connection alive)

WebSocket vs SSE vs Polling Comparison

AspectWebSocketSSELong Polling
DirectionFull duplex (bidirectional)Server to client onlyServer to client only
Protocolws:// / wss://Plain HTTPPlain HTTP
Browser supportAll modern browsersAll modern browsers (no IE)Universal
Auto-reconnectMust implement manuallyBuilt into EventSourceMust implement manually
Proxy/firewall friendlySometimes blockedYes — plain HTTPYes — plain HTTP
Multiplexing over HTTP/2No (separate connection)YesYes
Use caseChat, collaborative editing, gamingNotifications, live feeds, dashboardsFallback for environments blocking WS/SSE
Server loadHigh (persistent connections)High (persistent connections)Medium (connections cycle)

Scaling WebSocket Connections

WebSockets are stateful — a connection is pinned to a specific server. This creates challenges when scaling horizontally:

  • Sticky sessions required: The load balancer must route all requests from a given WebSocket client to the same server. If the server restarts, the connection is lost.
  • Message fan-out: If a message should be delivered to multiple connected clients (e.g., a chat room with users on different servers), you need a pub/sub backbone like Redis Pub/Sub or Kafka to broadcast across server instances.
  • Connection limits: A single server can realistically handle 10,000-100,000 concurrent WebSocket connections (depending on message frequency and memory). Design for horizontal scaling.
  • Heartbeats and keepalives: Send periodic ping frames to detect dead connections and keep the TCP connection through NAT devices and firewalls that have connection timeouts.
Loading diagram...
Redis Pub/Sub fans out messages across WebSocket servers so clients on any server receive messages
📌

Real-world: Slack's WebSocket architecture

Slack uses WebSockets for real-time message delivery. Each server handles thousands of persistent connections. Redis Pub/Sub fans messages out to all servers in a workspace's connection pool. When a server becomes overloaded or restarts, clients reconnect automatically with exponential backoff and receive missed messages by replaying from the point their connection dropped (tracked via message IDs).

💡

Interview Tip

When asked to design a real-time system (chat, notifications, live collaboration), explicitly address: (1) connection management — WebSocket vs SSE based on bidirectionality needs, (2) message persistence — where do you store messages so reconnecting clients can replay missed events, (3) fan-out — how do you deliver to all connected clients of a user who is connected to multiple servers, and (4) horizontal scaling — Redis Pub/Sub or Kafka for cross-server message delivery. These four points show architectural maturity.

📝

Knowledge Check

5 questions

Test your understanding of this lesson. Score 70% or higher to complete.

Ask about this lesson

Ask anything about WebSockets & Server-Sent Events