Socket.io is a library that enables real-time, bidirectional communication between client and server. Unlike HTTP which is request-response based, Socket.io keeps a persistent connection open — so server can push data to client anytime without client asking.
It is built on top of WebSocket protocol but also has fallback to HTTP long-polling if WebSocket is not supported.
Common use cases are chat applications, live notifications, real-time dashboards, and multiplayer games.
1. Client connects to server
↓
2. WebSocket handshake occurs (HTTP → WebSocket upgrade)
↓
3. Persistent connection established ✅
↓
4. Either client or server can emit any event
↓
5. The other side is listening for events (on)
↓
6. Real-time data exchange continues
↓
7. Client disconnect → connection closes
HTTP is request-response — client requests, server responds, connection closes. WebSocket is a persistent connection — both client and server can send data anytime. Socket.io is built on WebSocket.
WebSocket is a protocol — browser built-in. Socket.io is a library built on top of WebSocket that adds extra features like automatic reconnection, rooms, namespaces, and fallback to HTTP long-polling if WebSocket is not supported.
I use JWT authentication in Socket.io middleware. When client connects, it sends JWT token in the handshake. Server verifies the token before allowing connection — if invalid, connection is rejected. This ensures only authenticated users can connect and send events.
Room is a way to group multiple sockets together. For example in a chat app — each chat group is a room. When someone sends a message, we emit it only to that room instead of all connected users.
In middleware we use next(new Error()) to reject connection. On frontend we listen to connect_error event to handle connection failures and show user a proper message.
Socket.io has automatic reconnection built-in. It tries to reconnect with exponential backoff. On backend we listen to disconnect event to clean up — like removing user from active users list or updating their online status.
Good question — JWT is verified only at connection time, not on every event. So if token expires mid-connection, socket stays connected. To handle this, we can set a timer on backend matching token expiry and forcefully disconnect the socket, or validate token on sensitive events too.
We can use Socket.io with Redis adapter — this allows Socket.io to run on multiple server instances and share socket state. This makes it horizontally scalable.
HTTP polling means client keeps asking server every few seconds — wasteful. Long polling means client waits for server response. WebSocket/Socket.io is persistent connection — much more efficient, no repeated requests.
Sure! Let me explain a real-time chat application example.
**REAL EXAMPLE: Building a Chat Application**
**1. THINKING PROCESS (Why Socket.io?)**
- Traditional HTTP: User A sends message → HTTP request → Server → Response → User B has to refresh page to see message. Bad experience!
- With Socket.io: User A sends message → Server gets it instantly → Server sends to User B in real-time without refresh. Perfect!
- Problem: Multiple chat rooms exist. If I broadcast to ALL users, everyone gets every message. Bad!
- Solution: Use Socket.io ROOMS. Each chat room is a separate room. Messages only go to that room.
**2. IMPLEMENTATION STEPS**
Step 1: Server Setup (Node.js + Express)
```javascript
const express = require('express');
const http = require('http');
const socketIO = require('socket.io');
const app = express();
const server = http.createServer(app);
const io = socketIO(server, { cors: { origin: '*' } });
io.on('connection', (socket) => {
console.log('User connected:', socket.id);
});
server.listen(3000, () => console.log('Server running'));
```
Step 2: Join Room When User Enters Chat
```javascript
socket.on('joinRoom', (roomId, userName) => {
socket.join(roomId); // User joins specific room
socket.username = userName;
// Notify others in room that user joined
io.to(roomId).emit('userJoined', {
message: `${userName} joined the chat`,
usersCount: io.sockets.adapter.rooms.get(roomId).size
});
});
```
Step 3: Send Message to Room Only
```javascript
socket.on('sendMessage', (roomId, message) => {
const messageData = {
username: socket.username,
text: message,
timestamp: new Date()
};
// Send to only that room, not all users
io.to(roomId).emit('receiveMessage', messageData);
});
```
Step 4: Handle Disconnect
```javascript
socket.on('disconnect', () => {
console.log('User disconnected:', socket.id);
// User automatically leaves all rooms
});
```
**3. COMPLETE FLOW (Step by Step)**
User A in Chat Room 1:
1. Opens chat app → Frontend connects to server
2. Emits 'joinRoom' event with roomId='room1', userName='Alice'
↓
3. Server receives joinRoom event
4. socket.join('room1') — User A is now in room1
5. Server broadcasts 'userJoined' to ALL users in room1 only
↓
6. User B in room1 sees message "Alice joined the chat"
Now User A types message "Hello everyone":
1. Frontend emits 'sendMessage' event with roomId='room1', text='Hello everyone'
↓
2. Server receives sendMessage event
3. Server creates messageData object
4. Server emits 'receiveMessage' to room1 ONLY
↓
5. All users in room1 (User A, User B, User C) receive message
6. Message appears in UI instantly for all of them
↓
7. Users in room2, room3 DON'T receive this message
User A leaves chat:
1. User A closes browser or navigates away
2. Socket automatically disconnects
3. Server fires disconnect event
4. Server notifies room1: "Alice left the chat"
↓
5. All users in room1 see notification
**4. WHY THIS APPROACH?**
- Persistent connection: No need to poll repeatedly
- Real-time: Message appears instantly
- Rooms: Isolates messages. room1 doesn't interfere with room2
- Scalable: Can add Redis adapter later for multiple server instances
- Clean: Emit/on pattern is easy to understand
**5. KEY POINTS TO MENTION IN INTERVIEW**
- Socket.io creates persistent connection unlike HTTP
- Rooms feature prevents message leakage between groups
- I handle authentication with JWT in middleware
- Disconnect event automatically cleans up (Socket.io built-in)
- For production scale, would add Redis adapter for horizontal scaling
- All messages logged to database for persistence