WebSockets for Real-Time Communication
Build bidirectional real-time communication with WebSockets, handling connection management, reconnection, and fallbacks.
Note: This guide follows English-language naming conventions and terminology standards common in international development teams. Examples use English identifiers and comments to maximize compatibility across codebases and tooling.
Overview
WebSockets provide full-duplex, persistent communication between browsers and servers over a single TCP connection. Unlike HTTP polling, WebSockets enable real-time data flow with minimal latency, making them ideal for chat, live dashboards, multiplayer games, and collaborative editing.
When to Use
Use this resource when:
- Building chat applications or live comment systems
- Streaming real-time data to dashboards (stocks, metrics, IoT)
- Implementing multiplayer game state synchronization
- Creating collaborative editing tools (like Google Docs)
Solution
Server with ws (Node.js)
const WebSocket = require('ws');
const wss = new WebSocket.Server({ port: 8080 });
const clients = new Set();
wss.on('connection', (ws, req) => {
clients.add(ws);
console.log('Client connected:', req.socket.remoteAddress);
ws.on('message', (data) => {
const message = JSON.parse(data);
// Broadcast to all connected clients
clients.forEach(client => {
if (client.readyState === WebSocket.OPEN) {
client.send(JSON.stringify({
type: 'chat',
from: message.user,
text: message.text,
timestamp: Date.now()
}));
}
});
});
ws.on('close', () => clients.delete(ws));
ws.on('error', (err) => console.error('WebSocket error:', err));
});
Client Reconnection Logic
class ReconnectingWebSocket {
constructor(url) {
this.url = url;
this.ws = null;
this.reconnectInterval = 3000;
this.maxReconnectInterval = 30000;
this.connect();
}
connect() {
this.ws = new WebSocket(this.url);
this.ws.onopen = () => {
console.log('Connected');
this.reconnectInterval = 3000; // Reset backoff
};
this.ws.onmessage = (event) => {
const data = JSON.parse(event.data);
this.onMessage(data);
};
this.ws.onclose = () => {
console.log('Disconnected, reconnecting...');
setTimeout(() => this.connect(), this.reconnectInterval);
this.reconnectInterval = Math.min(
this.reconnectInterval * 2,
this.maxReconnectInterval
);
};
this.ws.onerror = (err) => console.error('WebSocket error:', err);
}
send(data) {
if (this.ws.readyState === WebSocket.OPEN) {
this.ws.send(JSON.stringify(data));
}
}
}
Explanation
WebSocket handshake upgrades an HTTP connection:
- Client sends upgrade request with Connection: Upgrade and Upgrade: websocket headers
- Server responds 101 Switching Protocols to confirm
- Bidirectional frames are exchanged over the persistent TCP socket
- Close handshake cleanly terminates the connection
Key differences from SSE:
- WebSockets are bidirectional; SSE is server-to-client only
- WebSockets use binary frames; SSE uses text/event-stream
- WebSockets need custom heartbeat/ping; SSE uses HTTP keep-alive
Variants
| Technology | Direction | Best For |
|---|---|---|
| WebSockets | Bidirectional | Chat, games, collaboration |
| SSE | Server-to-client | Live feeds, notifications |
| Long Polling | Server-to-client | Legacy browser support |
| MQTT over WebSocket | Pub/sub | IoT, telemetry |
Best Practices
- Implement heartbeat/ping: Detect dead connections with periodic ping/pong frames
- Authenticate during handshake: Pass JWT in query string or subprotocol
- Use rooms/channels: Do not broadcast everything to all clients
- Handle backpressure: Drop or queue messages if clients are slow
- Fallback to SSE: For clients behind strict proxies that block WebSockets
Common Mistakes
- No reconnection logic: Network hiccups permanently disconnect users
- Broadcasting to all clients: Scales poorly; use pub/sub or channel rooms
- Ignoring memory leaks: Closed connections not removed from client sets cause OOM
- Sending binary without framing: Always serialize structured data (JSON, Protobuf)
- Not handling proxy timeouts: Corporate proxies may kill idle connections after 30s
Frequently Asked Questions
Q: How many concurrent WebSocket connections can a server handle? A: Node.js handles ~10k-50k connections per core. Use Redis pub/sub or a message bus to scale horizontally.
Q: Can WebSockets work over HTTPS? A: Yes — use wss:// (WebSocket Secure). Browsers block mixed-content ws:// on HTTPS pages.
Q: What is the best fallback if WebSockets are blocked? A: Server-Sent Events for server-to-client; HTTP long polling for bidirectional needs.
Related Resources
Server-Sent Events with Node.js and Express
Implement real-time server-to-client push using Server-Sent Events in Node.js with Express, covering connection management, event types, reconnection logic, and backpressure handling
RecipeBuild a Bidirectional Chat with WebSocket and Node.js
How to build a real-time bidirectional chat application using WebSocket with room-based messaging, presence tracking, and message persistence
PatternMVC Pattern in Modern Frontend Applications
Apply the Model-View-Controller pattern to React and Vue applications to separate data, UI, and interaction logic for maintainable component architecture
RecipeExpress.js Middleware Composition Patterns
Build maintainable Express applications using middleware composition patterns for authentication, validation, error handling, request context propagation, and async route wrappers
RecipeURL Encoding and Decoding: encodeURI, encodeURIComponent, and Beyond
Master URL encoding in JavaScript and other languages with encodeURI, encodeURIComponent, plus-safe handling, RFC 3986 compliance, and decoding edge cases