WebSockets & Real-Time Apps

Socket.io Server Setup

18 min Lesson 6 of 35

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