Socket.IO Complete Guide | Real-Time Apps· Rooms
이 글의 핵심
Socket.IO is the standard library for real-time bidirectional communication in Node.js. This guide covers everything from basic emit/on patterns to production-ready rooms, namespaces, and authentication.
What This Guide Covers
Socket.IO enables real-time, bidirectional communication between browsers and servers. This guide covers the full stack — from a basic chat app to production patterns with rooms, namespaces, and Redis scaling.
Real-world insight: Replacing polling with Socket.IO reduced server load by 80% in a dashboard app — the difference between 60 requests/minute per user and a single persistent connection.
Setup
# Server
npm install socket.io express
# Client
npm install socket.io-client
1. Basic Server
import express from 'express';
import { createServer } from 'http';
import { Server } from 'socket.io';
const app = express();
const httpServer = createServer(app);
const io = new Server(httpServer, {
cors: { origin: "http://localhost:3000", methods: ["GET", "POST"] }
});
io.on('connection', (socket) => {
console.log('Client connected:', socket.id);
socket.on('message', (data) => {
console.log('Received:', data);
socket.emit('reply', { text: 'Got it!', timestamp: Date.now() });
});
socket.on('disconnect', () => {
console.log('Client disconnected:', socket.id);
});
});
httpServer.listen(3000);
2. Basic Client
import { io } from 'socket.io-client';
const socket = io('http://localhost:3000');
socket.on('connect', () => {
console.log('Connected with id:', socket.id);
socket.emit('message', { text: 'Hello server!' });
});
socket.on('reply', (data) => {
console.log('Server says:', data.text);
});
socket.on('disconnect', () => {
console.log('Disconnected');
});
3. Rooms
Rooms let you broadcast to a subset of connected clients — perfect for chat channels, game lobbies, or user-specific events.
io.on('connection', (socket) => {
// Join a room
socket.on('join-room', (roomId) => {
socket.join(roomId);
socket.to(roomId).emit('user-joined', { userId: socket.id });
});
// Send to a specific room
socket.on('room-message', ({ roomId, message }) => {
io.to(roomId).emit('new-message', {
from: socket.id,
message,
timestamp: Date.now(),
});
});
// Leave a room
socket.on('leave-room', (roomId) => {
socket.leave(roomId);
socket.to(roomId).emit('user-left', { userId: socket.id });
});
});
4. Broadcasting
| Method | Who receives it |
|---|---|
socket.emit() | Sender only |
socket.broadcast.emit() | Everyone except sender |
io.emit() | Everyone including sender |
io.to(room).emit() | Everyone in the room |
socket.to(room).emit() | Everyone in the room except sender |
io.on('connection', (socket) => {
// Announce to everyone else when someone joins
socket.broadcast.emit('user-online', { userId: socket.id });
// Global announcement from server
setInterval(() => {
io.emit('server-time', { time: new Date().toISOString() });
}, 5000);
});
5. Namespaces
Namespaces let you create isolated communication channels on the same server — useful for separating admin traffic from user traffic.
// Default namespace: /
io.on('connection', (socket) => {
socket.emit('welcome', 'Public namespace');
});
// Admin namespace: /admin
const adminNs = io.of('/admin');
adminNs.on('connection', (socket) => {
socket.emit('welcome', 'Admin namespace');
socket.on('kick-user', (userId) => {
// Only admins see this event
adminNs.emit('user-kicked', userId);
});
});
Client:
const userSocket = io('http://localhost:3000'); // /
const adminSocket = io('http://localhost:3000/admin'); // /admin
6. Acknowledgements
Acknowledgements give you request/response semantics over sockets.
// Server
socket.on('save-message', (message, callback) => {
try {
// Save to DB...
callback({ status: 'ok', id: 'msg-123' });
} catch (err) {
callback({ status: 'error', message: err.message });
}
});
// Client
socket.emit('save-message', { text: 'Hello' }, (response) => {
if (response.status === 'ok') {
console.log('Saved with id:', response.id);
}
});
7. Authentication
Authenticate connections via middleware before they’re established:
import jwt from 'jsonwebtoken';
io.use((socket, next) => {
const token = socket.handshake.auth.token;
if (!token) return next(new Error('Authentication required'));
try {
const payload = jwt.verify(token, process.env.JWT_SECRET);
socket.data.user = payload;
next();
} catch {
next(new Error('Invalid token'));
}
});
io.on('connection', (socket) => {
console.log('Authenticated user:', socket.data.user.id);
});
Client sends token on connection:
const socket = io('http://localhost:3000', {
auth: { token: localStorage.getItem('token') }
});
8. Scaling with Redis
For multiple Node.js instances, use the Redis adapter to share events:
npm install @socket.io/redis-adapter ioredis
import { createClient } from 'ioredis';
import { createAdapter } from '@socket.io/redis-adapter';
const pubClient = createClient({ host: 'localhost', port: 6379 });
const subClient = pubClient.duplicate();
io.adapter(createAdapter(pubClient, subClient));
Now io.emit() and room broadcasts work across all instances automatically.
React Integration
// hooks/useSocket.js
import { useEffect, useRef } from 'react';
import { io } from 'socket.io-client';
export function useSocket(url) {
const socketRef = useRef(null);
useEffect(() => {
socketRef.current = io(url);
return () => socketRef.current.disconnect();
}, [url]);
return socketRef.current;
}
// ChatRoom.jsx
export function ChatRoom({ roomId }) {
const socket = useSocket('http://localhost:3000');
const [messages, setMessages] = useState([]);
useEffect(() => {
if (!socket) return;
socket.emit('join-room', roomId);
socket.on('new-message', (msg) => setMessages(prev => [...prev, msg]));
return () => socket.off('new-message');
}, [socket, roomId]);
const send = (text) => socket.emit('room-message', { roomId, message: text });
return (/* render messages */);
}
Key Takeaways
- Rooms → group sockets for targeted broadcasts (chat channels, game sessions)
- Namespaces → isolate feature areas on the same server
- Acknowledgements → add request/response semantics when you need confirmation
- Redis adapter → required for horizontal scaling
- Middleware → handle auth once at connection time, not per-event
Socket.IO handles reconnection, fallbacks, and event buffering automatically — focus on your application logic, not transport reliability.
Frequently Asked Questions (FAQ)
Q. When would I use this in practice?
A. Build real-time applications with Socket.IO. Covers WebSocket, Rooms, Broadcasting, Namespaces, and authentication with …
Q. What should I read before this?
A. Follow the previous article or related articles links at the bottom of each post to learn in sequence.
Q. Where can I study this more deeply?
A. Check cppreference and the relevant library’s official documentation. The reference links at the end of the article are also worth using.
Related Articles (Internal Links)
Other articles related to this topic.
- NestJS Complete Guide | Build Scalable Node.js APIs
- RabbitMQ Complete Guide | Message Queues· Exchanges
Keywords Covered in This Article (Related Search Terms)
This article covers Socket.IO, WebSocket, Realtime, Node.js, Chat, Backend.