Node.js

WebSockets

Real-time bidirectional communication with Socket.io — server setup, client connection, event emitting, rooms, namespaces, broadcasts, and disconnect handling.

Socket.io Install & Server Setup: Install Socket.io and attach it to an existing HTTP server. Configure CORS for browser clients.
📄server.js
JS
// npm install socket.io

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:  'http://localhost:5173',   // frontend URL
        methods: ['GET', 'POST'],
    },
    pingTimeout:  60000,
    pingInterval: 25000,
});

// Make io accessible from controllers
app.set('io', io);

server.listen(3000, () => console.log('Socket.io server on port 3000'));
module.exports = { io };
Client Connection & Basic Events: Listen for client connections on the server and handle the fundamental connection lifecycle.
📄sockets/index.js
JS
const registerSocketHandlers = (io) => {
    io.on('connection', (socket) => {
        console.log(`Client connected: ${socket.id}`);

        // Receive event from client
        socket.on('message', (data) => {
            console.log('Received:', data);
        });

        // Send event back to this client only
        socket.emit('welcome', { message: `Hello ${socket.id}` });

        // Handle disconnect
        socket.on('disconnect', (reason) => {
            console.log(`Client ${socket.id} disconnected: ${reason}`);
        });
    });
};

module.exports = registerSocketHandlers;

// In server.js:
// const registerSocketHandlers = require('./sockets/index');
// registerSocketHandlers(io);
Emitting Events: Different emit targets — send to one client, all clients, or everyone except the sender.
📄sockets/index.js – emit patterns
JS
io.on('connection', (socket) => {

    // To this socket only
    socket.emit('event', { data: 'private' });

    // To all connected clients (including sender)
    io.emit('broadcast', { data: 'to everyone' });

    // To all clients EXCEPT the sender
    socket.broadcast.emit('news', { data: 'from someone else' });

    // Send acknowledgment (callback from client)
    socket.emit('ping', { time: Date.now() }, (ack) => {
        console.log('Client acknowledged:', ack);
    });

    // Emit to a specific socket ID
    const targetId = 'abc123';
    io.to(targetId).emit('private', { message: 'direct message' });

});
Rooms: Group sockets into named rooms for targeted broadcasts — perfect for chat rooms, game lobbies, or per-user channels.
📄sockets/chatHandler.js
JS
io.on('connection', (socket) => {

    // Join a room
    socket.on('joinRoom', (roomId) => {
        socket.join(roomId);
        console.log(`${socket.id} joined room: ${roomId}`);

        // Notify others in the room
        socket.to(roomId).emit('userJoined', { id: socket.id });

        // Emit only to members of this room (including sender)
        io.to(roomId).emit('roomInfo', { members: io.sockets.adapter.rooms.get(roomId)?.size });
    });

    // Leave a room
    socket.on('leaveRoom', (roomId) => {
        socket.leave(roomId);
        socket.to(roomId).emit('userLeft', { id: socket.id });
    });

    // Send message to room
    socket.on('chatMessage', ({ roomId, message }) => {
        io.to(roomId).emit('newMessage', {
            from:    socket.id,
            message,
            at:      new Date().toISOString(),
        });
    });

});
Namespaces: Create separate communication channels on the same Socket.io server — useful for separating admin, user, and support socket spaces.
📄sockets/namespaces.js
JS
// Admin namespace
const adminNsp = io.of('/admin');
adminNsp.use((socket, next) => {
    const token = socket.handshake.auth.token;
    if (!isValidAdminToken(token)) return next(new Error('Unauthorized'));
    next();
});
adminNsp.on('connection', (socket) => {
    console.log('Admin connected:', socket.id);
    socket.emit('adminWelcome', { msg: 'Admin panel ready' });
});

// Chat namespace
const chatNsp = io.of('/chat');
chatNsp.on('connection', (socket) => {
    socket.on('send', (msg) => {
        chatNsp.emit('receive', msg);   // broadcast within /chat namespace
    });
});

// Client connection (frontend)
// const adminSocket = io('http://localhost:3000/admin', { auth: { token: '...' } });
// const chatSocket  = io('http://localhost:3000/chat');
Disconnect & Cleanup Handling: Properly clean up user sessions, notify peers, and remove stale data when a socket disconnects.
📄sockets/presenceHandler.js
JS
const onlineUsers = new Map();   // socketId -> userId

io.on('connection', (socket) => {
    // Register user
    socket.on('register', (userId) => {
        onlineUsers.set(socket.id, userId);
        io.emit('onlineUsers', [...onlineUsers.values()]);
        console.log(`User ${userId} is online`);
    });

    // Disconnecting fires before rooms are left
    socket.on('disconnecting', () => {
        socket.rooms.forEach((room) => {
            if (room !== socket.id) {
                socket.to(room).emit('userLeft', { socketId: socket.id });
            }
        });
    });

    // Disconnect fires after cleanup
    socket.on('disconnect', (reason) => {
        const userId = onlineUsers.get(socket.id);
        onlineUsers.delete(socket.id);
        io.emit('onlineUsers', [...onlineUsers.values()]);
        console.log(`User ${userId} disconnected. Reason: ${reason}`);
    });
});