Socket.io Server Setup
Socket.io is the most popular library for implementing WebSocket communication in Node.js applications. It provides a robust, reliable real-time bidirectional communication layer that works even in challenging network conditions.
Installing Socket.io
First, create a new Node.js project and install the required dependencies:
# Create project directory
mkdir socketio-server
cd socketio-server
# Initialize npm project
npm init -y
# Install dependencies
npm install express socket.io
Note: Socket.io requires a Node.js HTTP server to work. We'll use Express as it provides a clean way to create the server and handle regular HTTP routes alongside WebSocket connections.
Creating a Basic Socket.io Server
Let's create a simple server that listens for WebSocket connections:
// server.js
const express = require('express');
const { createServer } = require('http');
const { Server } = require('socket.io');
// Create Express app
const app = express();
// Create HTTP server
const httpServer = createServer(app);
// Create Socket.io server
const io = new Server(httpServer);
// Serve static files (optional)
app.use(express.static('public'));
// Handle HTTP routes
app.get('/', (req, res) => {
res.send('<h1>Socket.io Server Running</h1>');
});
// Listen for WebSocket connections
io.on('connection', (socket) => {
console.log('A user connected:', socket.id);
// Handle disconnection
socket.on('disconnect', () => {
console.log('User disconnected:', socket.id);
});
});
// Start server
const PORT = 3000;
httpServer.listen(PORT, () => {
console.log(`Server running on http://localhost:${PORT}`);
});
Understanding the Connection Event
The connection event is triggered whenever a client successfully connects to the server. Each connection receives a unique socket object that represents that specific client:
io.on('connection', (socket) => {
// socket.id - unique identifier for this connection
console.log('New connection:', socket.id);
// socket.handshake - connection details
console.log('Handshake:', socket.handshake.address);
console.log('Headers:', socket.handshake.headers);
// socket.connected - boolean connection status
console.log('Is connected:', socket.connected);
});
Emitting Events from Server
The server can send events to clients using the emit() method:
io.on('connection', (socket) => {
// Emit to this specific client
socket.emit('welcome', 'Welcome to the server!');
// Emit to all clients
io.emit('userCount', io.engine.clientsCount);
// Emit to all clients except sender
socket.broadcast.emit('newUser', socket.id);
});
Tip: Use socket.emit() to send to one client, io.emit() to send to all clients, and socket.broadcast.emit() to send to all except the sender.
Listening for Events from Clients
Use socket.on() to listen for custom events from clients:
io.on('connection', (socket) => {
// Listen for chat message
socket.on('chatMessage', (data) => {
console.log('Message received:', data);
// Broadcast to all clients
io.emit('chatMessage', {
id: socket.id,
message: data.message,
timestamp: new Date()
});
});
// Listen for typing indicator
socket.on('typing', (isTyping) => {
socket.broadcast.emit('userTyping', {
userId: socket.id,
isTyping: isTyping
});
});
// Listen for custom events
socket.on('customEvent', (payload) => {
console.log('Custom event:', payload);
});
});
Server Configuration Options
Socket.io provides many configuration options to customize behavior:
const io = new Server(httpServer, {
// CORS configuration
cors: {
origin: 'http://localhost:5173',
methods: ['GET', 'POST'],
credentials: true
},
// Connection timeout
connectTimeout: 45000,
// Ping timeout
pingTimeout: 5000,
pingInterval: 10000,
// Maximum HTTP buffer size
maxHttpBufferSize: 1e6, // 1 MB
// Allow upgrades
allowUpgrades: true,
// Transports
transports: ['websocket', 'polling'],
// Cookie options
cookie: {
name: 'io',
httpOnly: true,
path: '/'
}
});
Handling CORS with Socket.io
When your client and server are on different origins, you need to configure CORS:
// Allow specific origin
const io = new Server(httpServer, {
cors: {
origin: 'http://localhost:5173',
methods: ['GET', 'POST']
}
});
// Allow multiple origins
const io = new Server(httpServer, {
cors: {
origin: [
'http://localhost:5173',
'http://localhost:3001',
'https://myapp.com'
],
credentials: true
}
});
// Allow all origins (development only!)
const io = new Server(httpServer, {
cors: {
origin: '*'
}
});
Warning: Never use origin: '*' in production! Always specify allowed origins explicitly to prevent security vulnerabilities.
Error Handling
Handle errors gracefully to prevent server crashes:
io.on('connection', (socket) => {
// Handle connection errors
socket.on('error', (error) => {
console.error('Socket error:', error);
});
// Handle disconnect with reason
socket.on('disconnect', (reason) => {
console.log('Disconnected:', reason);
if (reason === 'transport close') {
// Connection lost
} else if (reason === 'ping timeout') {
// Client didn't respond to ping
}
});
});
// Handle server-level errors
io.engine.on('connection_error', (err) => {
console.log('Connection error:', err.code);
console.log('Message:', err.message);
console.log('Context:', err.context);
});
Complete Server Example
const express = require('express');
const { createServer } = require('http');
const { Server } = require('socket.io');
const app = express();
const httpServer = createServer(app);
const io = new Server(httpServer, {
cors: {
origin: 'http://localhost:5173',
methods: ['GET', 'POST']
}
});
// Track connected users
const connectedUsers = new Map();
io.on('connection', (socket) => {
console.log(`User connected: ${socket.id}`);
// Add user to tracking
connectedUsers.set(socket.id, {
connectedAt: new Date(),
lastActivity: new Date()
});
// Send current user count
io.emit('userCount', connectedUsers.size);
// Handle chat messages
socket.on('message', (data) => {
connectedUsers.get(socket.id).lastActivity = new Date();
io.emit('message', {
id: socket.id,
message: data,
timestamp: new Date()
});
});
// Handle disconnection
socket.on('disconnect', () => {
console.log(`User disconnected: ${socket.id}`);
connectedUsers.delete(socket.id);
io.emit('userCount', connectedUsers.size);
});
});
httpServer.listen(3000, () => {
console.log('Server running on port 3000');
});
Exercise: Create a Socket.io server that:
- Tracks the number of connected clients
- Sends a welcome message to new connections with their socket ID
- Broadcasts a notification when a user joins or leaves
- Logs all connection and disconnection events with timestamps
- Implements proper CORS configuration for localhost:5173