Topic Overview

WebSockets: Concepts, Internals & Interview Use Cases

Learn WebSocket protocol for full-duplex, persistent communication between client and server. Understand handshake, frame format, and use cases.

Medium11 min read

WebSockets

Why This Matters

Think of WebSockets like a phone call versus sending letters. HTTP is like sending lettersโ€”you write a letter (request), send it, wait for a reply (response), then the connection closes. WebSockets is like a phone callโ€”you dial once, the connection stays open, and you can talk back and forth in real time.

This matters because many applications need real-time communication. Chat apps, live notifications, collaborative editing, gamingโ€”these all need the server to push data to the client immediately. With HTTP, the client would have to keep asking "any updates?" (polling), which wastes resources and adds latency. WebSockets lets the server push data instantly.

In interviews, when someone asks "How would you design a real-time chat system?", they're testing whether you understand WebSockets. Do you know when to use WebSockets vs HTTP? Do you understand the handshake process? Most engineers don't. They just use HTTP polling and wonder why their app feels slow.

What Engineers Usually Get Wrong

Most engineers think "WebSockets are always better than HTTP." But WebSockets have overheadโ€”they keep connections open, which consumes server resources. For simple request-response patterns, HTTP is simpler and more efficient. WebSockets make sense when you need bidirectional, real-time communication.

Engineers also forget to handle reconnection. WebSocket connections can drop (network issues, server restarts). If your client doesn't reconnect, users lose functionality. Always implement automatic reconnection with exponential backoff.

How This Breaks Systems in the Real World

A chat application was using HTTP pollingโ€”the client asked for new messages every 2 seconds. Under normal load, this worked. But during peak hours, the server was handling 10,000 clients, each polling every 2 seconds = 5,000 requests per second. The server couldn't handle the load. Response times spiked. The service became unusable.

The fix? Use WebSockets. Each client maintains one persistent connection. The server pushes messages immediately when they arrive. This reduced server load from 5,000 requests/second to just the actual messages (maybe 100/second). But the real lesson is: polling doesn't scale. Use WebSockets for real-time communication.

Another story: A service was using WebSockets but didn't implement reconnection. When the server restarted (deployment), all WebSocket connections dropped. The client didn't reconnect automatically. Users had to refresh the page to reconnect. This created a poor user experience. The fix? Implement automatic reconnection with exponential backoff. Detect connection drops and reconnect automatically.


What are WebSockets?

WebSocket provides:

  • Full-duplex communication: Both client and server can send data simultaneously
  • Persistent connection: Connection stays open (unlike HTTP)
  • Low overhead: Minimal protocol overhead after handshake
  • Real-time: Instant bidirectional communication

Use cases:

  • Real-time chat applications
  • Live notifications
  • Collaborative editing
  • Gaming
  • Financial tickers
  • Live sports scores

WebSocket vs HTTP

HTTP (Request-Response)

Client โ†’ Server: GET /api/data
Server โ†’ Client: Response (connection closes)

For updates: Client must poll repeatedly
  Client โ†’ Server: GET /api/data (poll 1)
  Client โ†’ Server: GET /api/data (poll 2)
  Client โ†’ Server: GET /api/data (poll 3)

Problems:

  • Polling overhead: Repeated requests
  • Latency: Delay between polls
  • Server load: Many unnecessary requests

WebSocket (Persistent Connection)

Client โ†” Server: Persistent connection
  Client โ†’ Server: Message 1
  Server โ†’ Client: Message 2
  Client โ†’ Server: Message 3
  Server โ†’ Client: Message 4
  (Connection stays open)

Benefits:

  • No polling: Server can push data immediately
  • Low latency: Instant communication
  • Efficient: Single connection, minimal overhead

WebSocket Handshake

WebSocket starts as HTTP request, then upgrades to WebSocket protocol.

Client Request

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

Key headers:

  • Upgrade: websocket
  • Connection: Upgrade
  • Sec-WebSocket-Key: Random base64-encoded key
  • Sec-WebSocket-Version: Protocol version (13)

Server Response

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

Key points:

  • Status 101: Switching Protocols
  • Sec-WebSocket-Accept: Computed from client key + magic string

Key Calculation

1import crypto from 'crypto';
2
3function computeAcceptKey(clientKey: string): string {
4 // Compute Sec-WebSocket-Accept from client key
5 const magicString = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
6 const combined = clientKey + magicString;
7 const sha1Hash = crypto.createHash('sha1').update(combined).digest();
8 return sha1Hash.toString('base64');
9}
10
11// Example
12const clientKey = "dGhlIHNhbXBsZSBub25jZQ==";
13const acceptKey clientKey

WebSocket Frame Format

After handshake, data sent in frames:

 0                   1                   2                   3
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-------+-+-------------+-------------------------------+
|F|R|R|R| opcode|M| Payload len |    Extended payload length    |
|I|S|S|S|  (4)  |A|     (7)     |             (16/64)           |
|N|V|V|V|       |S|             |   (if payload len==126/127)   |
| |1|2|3|       |K|             |                               |
+-+-+-+-+-------+-+-------------+ - - - - - - - - - - - - - - - +
|     Extended payload length continued, if payload len == 127  |
+ - - - - - - - - - - - - - - - +-------------------------------+
|                               |Masking-key, if MASK set to 1  |
+-------------------------------+-------------------------------+
| Masking-key (continued)       |          Payload Data         |
+-------------------------------- - - - - - - - - - - - - - - - +
:                     Payload Data continued ...                :
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
|                     Payload Data continued ...                |
+---------------------------------------------------------------+

Fields:

  • FIN: Final fragment (1) or more fragments (0)
  • RSV: Reserved bits
  • Opcode: Frame type (text, binary, close, ping, pong)
  • MASK: Masking key present (client must mask, server must not)
  • Payload length: Length of payload data
  • Masking key: 32-bit key (if MASK=1)
  • Payload data: Actual data

Examples

WebSocket Server

1import WebSocket from 'ws';
2
3const wss = new WebSocket.Server({ port: 8080 });
4
5wss.on('connection', (ws: WebSocket, req: any) => {
6 console.log('Client connected');
7
8 // Send welcome message
9 ws.send('Welcome to WebSocket server!');
10
11 // Handle messages
12 ws.on('message', (message: Buffer) => {

WebSocket Client

1// Create WebSocket connection
2const ws = new WebSocket('ws://localhost:8080');
3
4// Connection opened
5ws.onopen = () => {
6 console.log('Connected to server');
7 ws.send('Hello Server!');
8};
9
10// Receive message
11ws.onmessage = (event: MessageEvent) => {
12 console.log('Received:', event.data);
13};

WebSocket with Authentication

1import WebSocket from 'ws';
2import jwt from 'jsonwebtoken';
3
4const wss = new WebSocket.Server({
5 port: 8080,
6 verifyClient: (info: any) => {
7 // Verify token from query string or headers
8 const token = new URL(info.req.url, 'http://localhost').searchParams.get('token');
9
10 try {
11 jwt.verify(token!, 'secret')

WebSocket Reconnection

1class WebSocketClient {
2 private url: string;
3 private ws: WebSocket | null = null;
4 private reconnectInterval: number = 1000;
5 private maxReconnectInterval: number = 30000;
6 private reconnectDecay: number = 1.5;
7 private shouldReconnect: boolean = true;
8
9 constructor(url: string) {
10 this.url = url;
11 }
12
13 connect() {
14 ws url

Common Pitfalls

  • Not handling reconnection: Connection drops, client doesn't reconnect. Fix: Implement automatic reconnection with exponential backoff
  • No heartbeat/ping: Don't know if connection is alive. Fix: Send ping frames periodically, close if no pong
  • Not handling backpressure: Sending too fast, overwhelming server. Fix: Check bufferedAmount, throttle sending
  • Security issues: Not validating origin, no authentication. Fix: Validate origin, implement authentication
  • Memory leaks: Not cleaning up event listeners. Fix: Remove listeners on close, limit connection lifetime
  • Not handling frame fragmentation: Large messages split into multiple frames. Fix: Handle FIN bit, reassemble fragments

Interview Questions

Beginner

Q: What are WebSockets and why are they used instead of HTTP?

A:

WebSockets provide full-duplex, persistent connections between client and server.

Why used instead of HTTP:

  1. Real-time communication: Server can push data immediately (no polling)
  2. Lower latency: No HTTP overhead after handshake
  3. Efficient: Single persistent connection vs multiple HTTP requests
  4. Bidirectional: Both client and server can send data simultaneously

HTTP vs WebSocket:

HTTP (Request-Response):
  Client โ†’ Server: GET /api/data
  Server โ†’ Client: Response (connection closes)
  For updates: Must poll repeatedly

WebSocket (Persistent):
  Client โ†” Server: Persistent connection
  Server โ†’ Client: Push data immediately
  No polling needed

Use cases:

  • Real-time chat
  • Live notifications
  • Collaborative editing
  • Gaming
  • Financial tickers

Intermediate

Q: Explain the WebSocket handshake process and frame format.

A:

Handshake Process:

  1. Client Request (HTTP Upgrade)

    GET /chat HTTP/1.1
    Upgrade: websocket
    Connection: Upgrade
    Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
    Sec-WebSocket-Version: 13
    
  2. Server Response (101 Switching Protocols)

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

1import crypto from 'crypto';
2
3const acceptKey = crypto
4 .createHash('sha1')
5 .update(clientKey + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11")
6 .digest('base64');

Frame Format:

[FIN|RSV|Opcode|MASK|Payload Length|Masking Key|Payload Data]

Fields:

  • FIN: Final fragment (1) or more fragments (0)
  • Opcode: Frame type (0x1=text, 0x2=binary, 0x8=close, 0x9=ping, 0xA=pong)
  • MASK: Masking key present (client must mask, server must not)
  • Payload length: Length of data (7, 16, or 64 bits)
  • Masking key: 32-bit key (if MASK=1, client frames)
  • Payload data: Actual message data

After handshake:

  • Connection upgraded to WebSocket protocol
  • Data sent in frames (not HTTP)
  • Connection stays open until closed

Senior

Q: Design a scalable WebSocket system that handles millions of concurrent connections. How do you handle load balancing, message routing, and connection management?

A:

1class ScalableWebSocketSystem {
2 private servers: WebSocketServer[];
3 private loadBalancer: LoadBalancer;
4 private messageRouter: MessageRouter;
5 private connectionManager: ConnectionManager;
6 private pubsub: PubSub;
7
8 constructor() {
9 // Multiple WebSocket servers
10 this.servers = [
11 new WebSocketServer({ port: 8080 }),
12 new WebSocketServer({ port: 8081 }),
13 new WebSocketServer({ port:

Features:

  1. Load balancing: Distribute connections across servers
  2. Message routing: Route messages to correct server
  3. Pub/Sub: Cross-server communication via Redis
  4. Connection management: Track connections, handle disconnections
  5. Heartbeat: Keep connections alive, detect dead connections
  6. Rate limiting: Prevent abuse
  7. Scaling: Horizontal scaling with multiple servers

Failure Stories You'll Recognize

The Polling Storm: A chat application was using HTTP pollingโ€”the client asked for new messages every 2 seconds. Under normal load, this worked. But during peak hours, the server was handling 10,000 clients, each polling every 2 seconds = 5,000 requests per second. The server couldn't handle the load. Response times spiked. The service became unusable. The fix? Use WebSockets. Each client maintains one persistent connection. The server pushes messages immediately when they arrive. This reduced server load from 5,000 requests/second to just the actual messages.

The Connection Drop: A service was using WebSockets but didn't implement reconnection. When the server restarted (deployment), all WebSocket connections dropped. The client didn't reconnect automatically. Users had to refresh the page to reconnect. This created a poor user experience. The fix? Implement automatic reconnection with exponential backoff. Detect connection drops and reconnect automatically.

The Memory Leak: A service was using WebSockets for real-time notifications. Each connection stored event listeners. When connections closed, the listeners weren't removed. Over time, memory usage grew. After a week, the service ran out of memory and crashed. The fix? Always remove event listeners when connections close. Use weak references or connection pools.

What Interviewers Are Really Testing

They want to hear you talk about when to use WebSockets vs HTTP, connection management, and scaling strategies. Junior engineers say "use WebSockets for real-time." Senior engineers say "WebSockets for bidirectional real-time communication, HTTP for request-response. Always implement reconnection, heartbeat, and rate limiting. For scaling, use load balancing and pub/sub for cross-server communication."

When they ask "How would you design a real-time system?", they're testing:

  • Do you understand when WebSockets make sense vs HTTP?

  • Do you know how to handle connection drops and reconnection?

  • Can you design a scalable WebSocket system?

  • HTTP/1 vs HTTP/2 vs HTTP/3 - WebSockets start as HTTP connections then upgrade, understanding HTTP explains WebSocket handshake

  • TCP vs UDP - WebSockets use TCP for reliable bidirectional communication, understanding TCP explains WebSocket behavior

  • Three-Way Handshake (TCP) - WebSocket connections require TCP handshake, understanding TCP handshakes explains WebSocket connection establishment

  • Keep-Alive vs Long Polling - WebSockets are an alternative to long polling, understanding polling helps appreciate WebSocket benefits

  • Connection Pooling - WebSocket connections are persistent, understanding connection management helps optimize WebSocket usage

  • WebSocket: Full-duplex, persistent connection for real-time communication

  • Handshake: Starts as HTTP, upgrades to WebSocket (101 Switching Protocols)

  • Frame format: Binary frames with opcode, mask, payload length, data

  • Benefits: No polling, low latency, efficient, bidirectional

  • Use cases: Real-time chat, notifications, gaming, collaborative editing

  • Connection management: Handle reconnection, heartbeat, backpressure

  • Scaling: Load balancing, message routing, pub/sub for cross-server communication

  • Best practices: Implement reconnection, heartbeat, rate limiting, authentication

How InterviewCrafted Will Teach This

We'll teach this through production failures, not protocol specifications. Instead of memorizing "WebSocket uses a handshake," you'll learn through scenarios like "what happens when 10,000 clients poll every 2 seconds?"

You'll see how WebSockets affect performance, scalability, and user experience. When an interviewer asks "how would you design a real-time system?", you'll think about connection management, reconnection strategies, and scalingโ€”not just "use WebSockets."

Key Takeaways

WebSocket: Full-duplex, persistent connection for real-time communication

Handshake: Starts as HTTP, upgrades to WebSocket (101 Switching Protocols)

Frame format: Binary frames with opcode, mask, payload length, data

Benefits: No polling, low latency, efficient, bidirectional

Use cases: Real-time chat, notifications, gaming, collaborative editing

Connection management: Handle reconnection, heartbeat, backpressure

Scaling: Load balancing, message routing, pub/sub for cross-server communication

Best practices: Implement reconnection, heartbeat, rate limiting, authentication


About the author

InterviewCrafted helps you master system design with patience. We believe in curiosity-led engineering, reflective writing, and designing systems that make future changes feel calm.