Socket.io enables real-time, bidirectional communication between web clients and servers. This guide covers everything from basic setup to advanced patterns for production applications.
1. WebSocket Fundamentals
How WebSockets Work
- Persistent connection between client/server
- Low latency communication
- Full-duplex (simultaneous two-way)
- Event-driven architecture
Socket.io Features
- Automatic reconnection
- Room support
- Binary streaming
- Fallback to HTTP long-polling
- Broadcasting capabilities
2. Basic Setup
Server Implementation
const express = require('express');
const http = require('http');
const { Server } = require('socket.io');
const app = express();
const server = http.createServer(app);
const io = new Server(server, {
cors: {
origin: "https://yourdomain.com",
methods: ["GET", "POST"]
}
});
// Connection handler
io.on('connection', (socket) => {
console.log('New client connected:', socket.id);
socket.on('disconnect', () => {
console.log('Client disconnected:', socket.id);
});
});
server.listen(3000, () => {
console.log('Server running with Socket.io');
});
Client Implementation
<script src="/socket.io/socket.io.js"></script>
<script>
const socket = io('https://yourdomain.com', {
transports: ['websocket'],
upgrade: false
});
socket.on('connect', () => {
console.log('Connected to server');
});
socket.on('disconnect', () => {
console.log('Disconnected from server');
});
</script>
3. Core Communication Patterns
Basic Messaging
// Server
socket.on('chat message', (msg) => {
console.log('Message received:', msg);
io.emit('chat message', msg); // Broadcast to all
});
// Client
socket.emit('chat message', 'Hello world!');
socket.on('chat message', (msg) => {
console.log('New message:', msg);
});
Acknowledgment
// Server
socket.on('update settings', (data, callback) => {
try {
// Process data
callback({ status: 'success' });
} catch (err) {
callback({ status: 'error', message: err.message });
}
});
// Client
socket.emit('update settings', { theme: 'dark' }, (response) => {
console.log('Server response:', response);
});
4. Rooms and Namespaces
Room Implementation
// Join room
socket.on('join room', (roomId) => {
socket.join(roomId);
console.log(`Socket ${socket.id} joined room ${roomId}`);
});
// Leave room
socket.on('leave room', (roomId) => {
socket.leave(roomId);
});
// Broadcast to room
io.to('room1').emit('room message', 'Hello room!');
// Broadcast to all in room except sender
socket.to('room1').emit('room message', 'Hello others!');
Namespaces
// Create admin namespace
const adminIO = io.of('/admin');
adminIO.use((socket, next) => {
// Authentication middleware
if (socket.handshake.auth.token === 'admin-secret') {
next();
} else {
next(new Error('Not authorized'));
}
});
adminIO.on('connection', (socket) => {
console.log('Admin connected');
});
5. Advanced Patterns
State Management
// Track connected users
const users = new Map();
io.on('connection', (socket) => {
socket.on('register user', (userId) => {
users.set(socket.id, userId);
console.log(`User ${userId} connected`);
});
socket.on('disconnect', () => {
const userId = users.get(socket.id);
users.delete(socket.id);
console.log(`User ${userId} disconnected`);
});
});
Binary Streaming
// Sending files
socket.on('send file', (fileData) => {
// fileData could be ArrayBuffer, Blob, etc.
socket.broadcast.emit('receive file', fileData);
});
// With progress events
const stream = fs.createReadStream('large-file.zip');
stream.on('data', (chunk) => {
socket.emit('file chunk', chunk);
});
stream.on('end', () => {
socket.emit('file end');
});
6. Scaling Considerations
Multiple Servers Setup
const { createServer } = require('http');
const { Server } = require('socket.io');
const redisAdapter = require('socket.io-redis');
const io = new Server();
// Configure Redis adapter
io.adapter(redisAdapter({
host: 'redis-server',
port: 6379
}));
// Behind load balancer
io.attach(createServer(), {
pingInterval: 10000,
pingTimeout: 5000,
cookie: false
});
Load Balancing Requirements
- Sticky sessions required
- Configure WebSocket support in LB
- Health checks for long-lived connections
- Monitor connection counts per server
7. Security Best Practices
Authentication
// Middleware approach
io.use((socket, next) => {
const token = socket.handshake.auth.token;
if (verifyToken(token)) {
socket.user = decodeToken(token);
next();
} else {
next(new Error('Authentication error'));
}
});
// On connection
io.on('connection', (socket) => {
console.log('Authenticated user:', socket.user.id);
});
Rate Limiting
const rateLimit = require('socket.io-rate-limiter');
io.use(rateLimit({
windowMs: 60 * 1000, // 1 minute
delayAfter: 20, // 20 messages
delayMs: 1000, // 1s delay after limit
max: 100 // Max 100 messages/min
}));
// Per-event rate limiting
socket.on('chat message', rateLimit({
windowMs: 10000,
max: 5
}), (msg) => {
// Handler
});
Next: Microservices Architecture →
Socket.io Checklist
- ✅ Implement proper authentication
- ✅ Use rooms for targeted communication
- ✅ Handle disconnections gracefully
- ✅ Add rate limiting for public events
- ✅ Plan for scaling with Redis adapter
- ✅ Monitor connection counts and events