Episode 3 — NodeJS MongoDB Backend Architecture / 3.15 — Realtime Communication WebSockets
3.15 — Quick Revision: Realtime Communication & WebSockets
Rapid-fire revision notes for WebSocket concepts, Socket.io API, rooms, namespaces, and middleware.
WebSocket Protocol
- Full-duplex communication over a single TCP connection
- Starts with HTTP Upgrade handshake (101 Switching Protocols)
- Protocols:
ws://(unencrypted) andwss://(TLS encrypted -- always use in production) - Lifecycle: Open -> Message (many) -> Close
- Frame overhead: ~2-6 bytes (vs ~800+ bytes for HTTP headers)
- Use cases: chat, notifications, gaming, collaborative editing, live data
Polling vs SSE vs WebSocket
| Short Polling | Long Polling | SSE | WebSocket | |
|---|---|---|---|---|
| Direction | Client -> Server | Client -> Server | Server -> Client | Bidirectional |
| Latency | High | Medium | Low | Very Low |
| Bandwidth | Wasteful | Medium | Efficient | Most Efficient |
| Best for | Simple dashboards | Moderate updates | Server push only | Two-way real-time |
Socket.io Basics
// Server setup
const server = http.createServer(app);
const io = new Server(server, { cors: { origin: '*' } });
// Use server.listen(), NOT app.listen()
// Connection
io.on('connection', (socket) => {
socket.emit('event', data); // to this client
io.emit('event', data); // to ALL clients
socket.broadcast.emit('event', data); // to all EXCEPT sender
socket.on('disconnect', (reason) => {}); // cleanup
});
// Client
const socket = io('http://localhost:3000');
socket.on('connect', () => {});
socket.emit('event', data);
socket.on('event', (data) => {});
Rooms
socket.join('room'); // join
socket.leave('room'); // leave
io.to('room').emit('event', data); // all in room
socket.to('room').emit('event', data); // room except sender
const sockets = await io.in('room').fetchSockets(); // get members
// Sockets auto-leave all rooms on disconnect
Namespaces
const chatNs = io.of('/chat'); // create namespace
chatNs.on('connection', (socket) => {}); // handle connections
// Client: io('http://localhost:3000/chat')
// Namespaces = separate features; Rooms = groups within a feature
Middleware
io.use((socket, next) => {
const token = socket.handshake.auth.token; // get token
// verify -> socket.user = userData -> next()
// reject -> next(new Error('message'))
});
// Per-namespace: chatNs.use(middleware)
// Client error: socket.on('connect_error', (err) => {})
Key Gotchas
- Socket.io is NOT interoperable with raw WebSocket
app.listen()creates a separate server -- useserver.listen()insteaddisconnectingevent still hassocket.rooms;disconnectdoes not- React Strict Mode causes double mount -- clean up listeners in useEffect return
- Configure CORS when frontend/backend are on different origins
- Rooms are server-side only -- clients do not know which rooms they are in