WebSockets & Real-Time Communication
📖 Concept
WebSockets enable bidirectional, full-duplex communication between client and server over a single TCP connection. Unlike HTTP (request → response), WebSockets allow the server to push data to clients at any time.
WebSocket vs HTTP:
| Feature | HTTP | WebSocket |
|---|---|---|
| Direction | Client → Server | Bidirectional |
| Connection | New for each request | Persistent |
| Overhead | Headers per request | Minimal after handshake |
| Latency | Higher (new connection) | Low (persistent) |
| Use case | REST APIs, page loads | Chat, live updates, games |
Server-Sent Events (SSE) vs WebSockets:
| Feature | SSE | WebSocket |
|---|---|---|
| Direction | Server → Client only | Bidirectional |
| Protocol | HTTP | Custom (ws://) |
| Reconnection | Automatic | Manual |
| Browser support | All modern browsers | All modern browsers |
| Use case | Live feeds, notifications | Chat, collaboration, games |
Socket.IO is the most popular WebSocket library for Node.js. It adds:
- Automatic reconnection
- Room-based broadcasting
- Binary data support
- Fallback to HTTP long-polling
- Acknowledgements (callback on message delivery)
🏠 Real-world analogy: HTTP is like sending letters — you send a request, wait for a reply. WebSockets are like a phone call — once connected, either party can speak at any time, and the line stays open. Socket.IO is like a conference call app — it handles reconnection, group calls (rooms), and ensures delivery.
💻 Code Example
1// WebSockets with Socket.IO — Real-Time Chat23const express = require("express");4const { createServer } = require("http");5const { Server } = require("socket.io");67const app = express();8const httpServer = createServer(app);9const io = new Server(httpServer, {10 cors: { origin: "*", methods: ["GET", "POST"] },11 pingTimeout: 60000,12 pingInterval: 25000,13});1415app.use(express.static("public"));1617// Track online users18const onlineUsers = new Map();1920// 1. Connection handling21io.on("connection", (socket) => {22 console.log(`User connected: ${socket.id}`);2324 // 2. User joins with username25 socket.on("user:join", (username) => {26 onlineUsers.set(socket.id, { username, joinedAt: Date.now() });27 socket.username = username;2829 // Broadcast to all clients30 io.emit("user:online", {31 users: Array.from(onlineUsers.values()),32 count: onlineUsers.size,33 });3435 // Notify others36 socket.broadcast.emit("system:message", {37 text: `${username} joined the chat`,38 timestamp: Date.now(),39 });40 });4142 // 3. Chat messages43 socket.on("chat:message", (data) => {44 const message = {45 id: Date.now().toString(),46 text: data.text,47 username: socket.username,48 timestamp: Date.now(),49 };5051 // Send to everyone (including sender)52 io.emit("chat:message", message);53 });5455 // 4. Rooms (channels)56 socket.on("room:join", (roomName) => {57 socket.join(roomName);58 socket.to(roomName).emit("system:message", {59 text: `${socket.username} joined #${roomName}`,60 room: roomName,61 });62 });6364 socket.on("room:message", ({ room, text }) => {65 io.to(room).emit("chat:message", {66 id: Date.now().toString(),67 text,68 username: socket.username,69 room,70 timestamp: Date.now(),71 });72 });7374 socket.on("room:leave", (roomName) => {75 socket.leave(roomName);76 });7778 // 5. Typing indicator79 socket.on("user:typing", (data) => {80 socket.broadcast.emit("user:typing", {81 username: socket.username,82 isTyping: data.isTyping,83 });84 });8586 // 6. Acknowledgements (delivery confirmation)87 socket.on("chat:private", (data, callback) => {88 const { to, text } = data;89 const targetSocket = [...io.sockets.sockets.values()].find(90 (s) => s.username === to91 );9293 if (targetSocket) {94 targetSocket.emit("chat:private", {95 from: socket.username,96 text,97 timestamp: Date.now(),98 });99 callback({ delivered: true });100 } else {101 callback({ delivered: false, reason: "User not online" });102 }103 });104105 // 7. Disconnection106 socket.on("disconnect", (reason) => {107 console.log(`User disconnected: ${socket.username} (${reason})`);108 onlineUsers.delete(socket.id);109110 io.emit("user:online", {111 users: Array.from(onlineUsers.values()),112 count: onlineUsers.size,113 });114115 if (socket.username) {116 io.emit("system:message", {117 text: `${socket.username} left the chat`,118 timestamp: Date.now(),119 });120 }121 });122});123124// 8. Server-Sent Events (SSE) endpoint — simpler alternative125app.get("/api/events", (req, res) => {126 res.writeHead(200, {127 "Content-Type": "text/event-stream",128 "Cache-Control": "no-cache",129 Connection: "keep-alive",130 });131132 const intervalId = setInterval(() => {133 const data = JSON.stringify({ timestamp: Date.now(), message: "heartbeat" });134 res.write(`data: ${data}\n\n`);135 }, 5000);136137 req.on("close", () => {138 clearInterval(intervalId);139 });140});141142const PORT = process.env.PORT || 3000;143httpServer.listen(PORT, () => {144 console.log(`Server running on http://localhost:${PORT}`);145});
🏋️ Practice Exercise
Exercises:
- Build a real-time chat application with Socket.IO — support usernames, message history, and online user list
- Implement chat rooms (channels) with join/leave and room-specific messaging
- Add typing indicators that show when other users are typing
- Implement private messaging with delivery acknowledgements
- Build a real-time notification system using Server-Sent Events (SSE)
- Scale Socket.IO horizontally across multiple servers using the Redis adapter
⚠️ Common Mistakes
Not implementing reconnection logic — network disruptions are common; Socket.IO handles this automatically, but raw WebSocket requires manual reconnection
Broadcasting to all sockets including the sender — use
socket.broadcast.emit()(excludes sender) vsio.emit()(includes sender) correctlyNot authenticating WebSocket connections — validate tokens in the handshake middleware, not after connection
Storing WebSocket state only in memory — when scaling to multiple servers, use Redis adapter for Socket.IO to share state
Using WebSockets for everything — simple one-way updates are better served by SSE (simpler, auto-reconnect); use WebSockets only when bidirectional communication is needed
💼 Interview Questions
🎤 Mock Interview
Mock interview is powered by AI for WebSockets & Real-Time Communication. Login to unlock this feature.