What is WebSocket? — Real-Time Communication Protocol Explained
Definition
WebSocket is a computer communications protocol that provides full-duplex communication channels over a single TCP connection. Unlike traditional HTTP request-response models, WebSocket enables persistent, bidirectional data exchange between a client and a server with minimal overhead. The protocol was standardized as RFC 6455 by the IETF in 2011 and is widely supported by all modern web browsers.
WebSocket transforms the web from a page-oriented, request-response model into a platform capable of real-time, event-driven communication — making it the foundation for modern live applications.
WebSocket vs HTTP
| Aspect | WebSocket | HTTP |
|---|---|---|
| Connection | Persistent (stays open) | Short-lived (closed after response) |
| Direction | Bidirectional (full-duplex) | Unidirectional (request → response) |
| Overhead | Low (2 bytes framing after handshake) | High (headers per request) |
| Latency | Low — server pushes instantly | Higher — client must poll |
| Protocol | ws:// / wss:// |
http:// / https:// |
| Handshake | HTTP upgrade (one-time) | Per-request |
| Streaming | Native | Requires SSE, chunked encoding, or long polling |
| Binary Data | Native support (Blob, ArrayBuffer) | Requires Base64 or multipart encoding |
| Browser Support | All modern browsers | Universal |
The key difference: HTTP treats each interaction as a separate transaction. WebSocket opens a single connection and keeps it alive for ongoing, low-latency message exchange.
The WebSocket Handshake
WebSocket communication begins with an HTTP upgrade handshake — the only HTTP request the connection ever makes:
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.comServer Response
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=The server computes the Sec-WebSocket-Accept value by concatenating the client's Sec-WebSocket-Key with the fixed GUID 258EAFA5-E914-47DA-95CA-C5AB0DC85B11, then taking the SHA-1 hash and Base64-encoding the result. Once the handshake completes, the TCP connection is fully upgraded to the WebSocket protocol and either side can begin sending data frames at any time.
WebSocket Frame Format
WebSocket data travels in discrete units called frames. Each frame has a compact binary structure:
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) |
+---------------------------------------------------------------+
Key Fields
| Field | Description |
|---|---|
| FIN | 1 bit — marks the final fragment of a message |
| RSV1-3 | 3 bits — reserved for extensions (must be 0 unless negotiated) |
| Opcode | 4 bits — defines frame type: 0x1 (text), 0x2 (binary), 0x8 (close), 0x9 (ping), 0xA (pong) |
| MASK | 1 bit — if set, payload is masked (required for client-to-server frames) |
| Payload Length | 7 bits, 7+16 bits, or 7+64 bits — length of the payload data |
| Masking Key | 32 bits — random XOR mask (present only when MASK = 1) |
| Payload Data | The actual application data (text or binary) |
Frames can be fragmented — a large message may be split across multiple frames using the FIN bit to signal the final fragment.
Client-Side JavaScript API
Browsers expose WebSocket through the native WebSocket interface:
// Connect to a WebSocket server
const socket = new WebSocket("wss://example.com/ws");
// Connection opened
socket.addEventListener("open", (event) => {
console.log("Connected to server");
socket.send("Hello server!");
});
// Listen for messages
socket.addEventListener("message", (event) => {
console.log("Message from server:", event.data);
// event.data can be a string, Blob, or ArrayBuffer
});
// Handle errors
socket.addEventListener("error", (event) => {
console.error("WebSocket error:", event);
});
// Connection closed
socket.addEventListener("close", (event) => {
console.log("Disconnected:", event.code, event.reason);
// event.code: 1000 (normal), 1006 (abnormal), etc.
// event.reason: human-readable close reason
});
// Send data — text or binary
socket.send("Hello!"); // text
socket.send(new Blob([data])); // binary (Blob)
socket.send(new TextEncoder().encode("Hi")); // binary (ArrayBuffer)
// Close the connection
socket.close(1000, "Client closing");Connection States
| State | Value | Description |
|---|---|---|
CONNECTING |
0 | Socket created, handshake not yet completed |
OPEN |
1 | Connection established, ready to send/receive |
CLOSING |
2 | Close handshake in progress |
CLOSED |
3 | Connection closed or failed to open |
Binary Type
By default, binary messages arrive as Blob objects. Switch to ArrayBuffer for direct byte access:
socket.binaryType = "arraybuffer";Server-Side Considerations
Node.js with the ws Library
The most popular WebSocket server implementation for Node.js is the ws library:
import { WebSocketServer } from "ws";
const wss = new WebSocketServer({ port: 8080 });
wss.on("connection", (ws, req) => {
console.log("Client connected from:", req.socket.remoteAddress);
// Send a welcome message
ws.send(JSON.stringify({ type: "welcome", message: "Connected!" }));
// Handle incoming messages
ws.on("message", (data) => {
console.log("Received:", data.toString());
// Broadcast to all connected clients
wss.clients.forEach((client) => {
if (client.readyState === WebSocket.OPEN) {
client.send(data);
}
});
});
// Handle disconnection
ws.on("close", (code, reason) => {
console.log("Client disconnected:", code, reason.toString());
});
});Other Server Libraries
| Language | Library | Notes |
|---|---|---|
| Node.js | ws |
Fast, low-level, most popular |
| Node.js | socket.io |
Higher-level, includes fallback, rooms, namespaces |
| Python | websockets |
Asyncio-based, clean API |
| Python | fastapi + websockets |
Built-in WebSocket support in FastAPI |
| Go | gorilla/websocket |
Battle-tested, widely used |
| Go | nhooyr.io/websocket |
Modern, minimal API |
| Java | javax.websocket (JSR 356) |
Standard Java EE API |
| Java | Spring WebSocket | Spring Framework abstraction |
| Rust | tungstenite |
Low-level, async-ready |
| Rust | tokio-tungstenite |
Async WebSocket with tokio |
| C# / .NET | ASP.NET Core SignalR | Full-featured real-time framework |
| Elixir | Phoenix Channels | Built on Erlang/OTP, excellent for real-time |
Common Use Cases
Real-Time Chat and Messaging
WebSocket powers instant messaging apps where sub-second delivery matters — from Slack and Discord to customer support chat widgets.
Live Updates and Notifications
Dashboards, notification systems, and activity feeds push updates as they happen without requiring page refreshes or polling.
Online Gaming
Multiplayer games require low-latency, high-frequency data exchange for player positions, actions, and game state synchronization.
Collaborative Editing
Google Docs, Notion, and VS Code Live Share use WebSocket (or similar persistent connections) to synchronize edits across participants in real time.
Financial Tickers
Stock prices, cryptocurrency rates, and trading platforms stream live market data through WebSocket connections to minimize latency.
IoT Device Communication
WebSocket provides persistent connections for sensor data streaming, device control, and status monitoring in real-time IoT systems.
Live Sports and Event Streaming
Score updates, race tracking, and live event data push to viewers without manual refresh.
WebSocket vs SSE vs Long Polling
| Aspect | WebSocket | Server-Sent Events (SSE) | Long Polling |
|---|---|---|---|
| Protocol | WebSocket (RFC 6455) | HTTP (EventSource API) | HTTP |
| Direction | Bidirectional (full-duplex) | Server → Client only (simplex) | Client-initiated request/response |
| Transport | Single persistent TCP connection | Single persistent HTTP connection | Repeated HTTP requests |
| Latency | Very low | Low | Moderate to high |
| Binary Data | Native binary support | Text-only (UTF-8) | Text or binary (via HTTP) |
| Auto-Reconnect | Manual implementation | Built-in (EventSource) | Manual implementation |
| Max Concurrent Connections | Unlimited (browser: ~6 per domain) | 6 per domain (HTTP/1.1) | Unlimited (but resource-intensive) |
| Browser Support | All modern browsers | All modern browsers (no IE) | Universal |
| Complexity | Medium | Low | Low |
| Best For | Real-time games, chat, collaborative apps | Live scores, notifications, log streams | Legacy browser support, simple updates |
When to Use Which
- Choose WebSocket when you need bidirectional, low-latency communication — chat, gaming, collaborative editing, financial tickers.
- Choose SSE when the server only needs to push data to the client — live feed updates, notifications, log streaming — and you want simpler implementation.
- Choose Long Polling as a fallback for environments where WebSocket or SSE aren't available, or for simple periodic updates where real-time isn't critical.
Security Considerations
Always Use wss:// (WebSocket Secure)
wss:// — WebSocket over TLS (encrypted, recommended)
ws:// — Unencrypted (avoid in production)
Just as HTTPS protects HTTP traffic, WSS encrypts WebSocket traffic using TLS. Never use unencrypted ws:// in production — it exposes all messages to man-in-the-middle attacks.
Origin Header Validation
Servers must validate the Origin header during the WebSocket handshake to prevent cross-site WebSocket hijacking. Only allow connections from trusted origins:
const wss = new WebSocketServer({
verifyClient: (info) => {
const allowedOrigins = ["https://yourapp.com"];
return allowedOrigins.includes(info.origin);
},
});Authentication and Authorization
WebSocket itself does not handle authentication. Common patterns include:
-
Token in the URL — Pass an auth token as a query parameter during handshake:
wss://example.com/ws?token=eyJhbGci... -
Token in the first message — Authenticate in the
onopencallback after the connection is established. -
Cookie-based auth — Since the WebSocket handshake is an HTTP upgrade, existing session cookies can be validated server-side.
Input Validation and Rate Limiting
- Validate and sanitize every incoming message — treat WebSocket input like any other untrusted user input.
- Implement rate limiting to prevent abuse (message flood attacks).
- Set reasonable message size limits to prevent memory exhaustion.
Close Code Hygiene
Use appropriate close codes (1000 for normal, 1008 for policy violation, 1011 for unexpected server error) to signal the reason for disconnection.
LangStop WebSocket and API Tools
- WebSocket Client — Test and debug WebSocket connections in your browser
- REST API Client — Make HTTP requests and test REST endpoints
- API Tools Hub — Browse all API testing and debugging utilities