Node.js WebSockets

WebSockets provide a full-duplex communication channel over a single, long-lived connection between a client and a server. Unlike HTTP, where the client always initiates requests and waits for a response, WebSockets allow both the client and the server to send messages to each other at any time — making them ideal for real-time applications.

Think of HTTP like sending letters back and forth — one side sends a letter, waits for a reply, then sends another. WebSockets are like a phone call — both sides can speak and listen simultaneously for as long as needed.

HTTP vs WebSockets

FeatureHTTPWebSocket
ConnectionOpens and closes for each requestStays open persistently
DirectionClient-to-server (request/response)Bidirectional (both ways)
Real-timeNot suitable (polling needed)Built for real-time
OverheadHeaders sent with every requestMinimal overhead after handshake
Use CasesFetching pages, REST APIsChat apps, live feeds, games

Use Cases for WebSockets

  • Real-time chat applications
  • Live sports scores and news feeds
  • Collaborative tools (like Google Docs)
  • Multiplayer browser games
  • Live financial dashboards and stock tickers
  • Real-time notifications

Socket.IO – The Most Popular WebSocket Library for Node.js

Socket.IO is a library that builds on WebSockets and adds features like automatic reconnection, room management, broadcasting, and fallback to HTTP polling in environments where WebSockets are not available. It consists of two parts: a Node.js server library and a client-side JavaScript library.

Installing Socket.IO

npm install express socket.io

Building a Basic Real-Time Chat Application

Project Structure

chat-app/
├── app.js
├── public/
│   └── index.html
└── package.json

app.js – Server

const express = require('express');
const http = require('http');
const { Server } = require('socket.io');
const path = require('path');

const app = express();
const server = http.createServer(app); // Create HTTP server from Express app
const io = new Server(server);          // Attach Socket.IO to the server

// Serve the HTML client file
app.use(express.static(path.join(__dirname, 'public')));

// Track connected users
let connectedUsers = 0;

// Handle WebSocket connections
io.on('connection', function(socket) {
  connectedUsers++;
  console.log(`User connected. Total users: ${connectedUsers}`);

  // Notify all clients that someone joined
  io.emit('user-joined', { count: connectedUsers });

  // Listen for incoming chat messages from this client
  socket.on('send-message', function(data) {
    console.log('Message received:', data.message);

    // Broadcast the message to ALL connected clients (including sender)
    io.emit('receive-message', {
      user: data.user,
      message: data.message,
      time: new Date().toLocaleTimeString()
    });
  });

  // Handle disconnection
  socket.on('disconnect', function() {
    connectedUsers--;
    console.log(`User disconnected. Total users: ${connectedUsers}`);
    io.emit('user-left', { count: connectedUsers });
  });
});

server.listen(3000, () => {
  console.log('Chat server running at http://localhost:3000');
});

public/index.html – Client

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Real-Time Chat</title>
</head>
<body>
  <h1>Real-Time Chat Room</h1>
  <p id="user-count">Users online: 0</p>

  <div id="messages"></div>

  <input type="text" id="username" placeholder="Your name" />
  <input type="text" id="message-input" placeholder="Type a message..." />
  <button onclick="sendMessage()">Send</button>

  <script src="/socket.io/socket.io.js"></script>
  <script>
    const socket = io();

    // Display incoming messages
    socket.on('receive-message', function(data) {
      const messagesDiv = document.getElementById('messages');
      const p = document.createElement('p');
      p.textContent = `[${data.time}] ${data.user}: ${data.message}`;
      messagesDiv.appendChild(p);
    });

    // Update user count
    socket.on('user-joined', function(data) {
      document.getElementById('user-count').textContent = 'Users online: ' + data.count;
    });

    socket.on('user-left', function(data) {
      document.getElementById('user-count').textContent = 'Users online: ' + data.count;
    });

    // Send message to server
    function sendMessage() {
      const user = document.getElementById('username').value || 'Anonymous';
      const message = document.getElementById('message-input').value;

      if (message.trim()) {
        socket.emit('send-message', { user, message });
        document.getElementById('message-input').value = '';
      }
    }
  </script>
</body>
</html>

Socket.IO Key Concepts

Emitting Events

// Emit to the current client only
socket.emit('eventName', data);

// Emit to ALL connected clients (including sender)
io.emit('eventName', data);

// Emit to ALL clients EXCEPT the sender
socket.broadcast.emit('eventName', data);

Rooms – Grouping Clients

Rooms allow messages to be sent only to specific groups of clients:

// Join a room
socket.join('room-name');

// Send a message to everyone in a specific room
io.to('room-name').emit('message', 'Hello to everyone in this room!');

// Leave a room
socket.leave('room-name');

Rooms are useful for building features like private chat channels or game lobbies.

Sending Data Back to the Sender Only

io.on('connection', function(socket) {
  socket.emit('welcome', { message: 'You are connected!' });
});

Handling Disconnections Gracefully

io.on('connection', function(socket) {
  const userId = socket.id;
  console.log('Connected:', userId);

  socket.on('disconnect', function(reason) {
    console.log(`User ${userId} disconnected. Reason: ${reason}`);
  });
});

Key Points

  • WebSockets provide a persistent, full-duplex connection — both client and server can send messages at any time.
  • HTTP is request-response (client initiates); WebSockets are bidirectional (either side can initiate).
  • Socket.IO is the most popular WebSocket library for Node.js. It adds reconnection, rooms, and broadcasting features.
  • Socket.IO requires creating an HTTP server from Express first, then attaching Socket.IO to it.
  • socket.emit() sends to one client; io.emit() sends to all; socket.broadcast.emit() sends to all except the sender.
  • Rooms allow messages to be scoped to a group of clients — essential for building chat channels or game lobbies.
  • Always handle the 'disconnect' event to clean up user state when a client leaves.

Leave a Comment

Your email address will not be published. Required fields are marked *