Real-Time Backend
Socket.IO Fundamentals
Цели урока
- Understand the Socket.IO handshake and upgrade mechanism
- Distinguish Namespace from Room and choose the right isolation level
- Use acknowledgements for reliable event delivery
- Understand the polling fallback strategy and its trade-offs
In 2016, WhatsApp served 1 billion users with a team of 50 engineers. The foundation was a protocol with reconnection, acknowledgements, and multiplexing. Socket.IO delivers all of that out of the box in five lines of code.
- **Slack** - Namespace per workspace, Rooms per channel, Ack for delivery guarantees
- **Figma** - real-time collaboration: each document is a separate Socket.IO Room
- **Trello** - live updates with polling fallback for enterprise clients behind proxies
Socket.IO: handshake and upgrade
HTTP is request-response: a server cannot push data without being asked first. **Socket.IO** addresses this in three steps: it starts with HTTP long-polling (works everywhere), attempts a **WebSocket upgrade**, and if the upgrade succeeds - stays on WebSocket permanently.
The first request is the **handshake**: the client receives a `sid` (session identifier), `pingInterval`, `pingTimeout`, and a list of available transports. Polling begins immediately while the client simultaneously attempts the WebSocket upgrade.
Socket.IO is **not** just WebSocket. On top of it (or polling) sits a custom protocol: automatic ping/pong, reconnection on disconnect, acknowledgements, and namespace multiplexing.
Socket.IO starts with long-polling rather than WebSocket directly. The main reason:
Rooms and Namespaces
A messaging app has thousands of chats, but each user should only receive messages from their own. Socket.IO provides two grouping levels: **Namespace** (separate application domains on one server) and **Room** (groups of sockets within a namespace).
A **Namespace** is a separate endpoint: `/chat`, `/admin`, `/notifications`. Different namespaces are isolated - events from `/chat` do not reach `/admin`. A **Room** is a dynamic group within a namespace. A socket can belong to multiple rooms simultaneously, and every socket automatically joins a personal room named after its `socket.id`.
When should a separate Namespace be used instead of a Room?
Acknowledgements and reliability
WebSocket is fire-and-forget: a packet is sent, and there is no built-in confirmation that it arrived. For a chat application this is a problem - a user sees a "sent" checkmark, but the message may have been lost. **Acknowledgements** (ack) solve this: the sender waits for an explicit confirmation from the receiver before treating the event as delivered.
An ack is not an automatic delivery guarantee. It is an **application-layer confirmation**: the server received the event, processed it, and returned a result. If the connection breaks before the ack arrives, Socket.IO will reconnect, but the event will not be re-sent automatically. That responsibility lies with the application.
For true at-least-once delivery, idempotent logic is required: the client stores each event with a unique `clientEventId` and retransmits on reconnect; the server deduplicates by that id.
A Socket.IO acknowledgement guarantees that a message:
Fallback: polling transport
Corporate networks often block WebSocket: proxies do not understand `Upgrade: websocket` and terminate the connection. Socket.IO automatically falls back to **HTTP long-polling** - the browser sends a GET request, the server holds it open until an event arrives (or a timeout), and then the client immediately issues the next request.
When WebSocket is unavailable due to a proxy and low latency is critical, consider **Server-Sent Events** for server-to-client direction and HTTP POST for client-to-server. SSE passes through most proxies and is faster than polling.
Socket.IO is configured with `transports: ['polling', 'websocket']`. WebSocket is blocked by a corporate proxy. The outcome:
Socket.IO Fundamentals
- Handshake issues a sid, starts with polling, then upgrades to WebSocket
- Namespace: middleware and logic isolation for separate application endpoints
- Room: dynamic groups within a namespace for targeted broadcast
- Acknowledgements: callback confirms application-level processing
- Polling fallback is transparent to the application; the API does not change
Related Topics
Socket.IO builds on WebSocket and addresses problems found throughout the real-time stack.
- WebSocket Protocol — Socket.IO uses WebSocket as its primary transport with a custom protocol on top
- Server-Sent Events — An alternative to the polling transport for the server-to-client direction
- Socket.IO Advanced — Middleware, binary data, volatile events and Redis Adapter for scaling
Вопросы для размышления
- When does it make sense to abandon Socket.IO in favor of the native WebSocket API?
- How can at-least-once delivery be built on top of acknowledgements under unstable connections?
- In what scenarios is a Namespace preferable to running separate Socket.IO servers?
Связанные уроки
- rt-05 — Socket.IO runs on WebSocket by default; understanding the transport is required
- rt-08 — Socket.IO serialization choices (JSON + binary) become clear after the serialization lesson
- rt-10 — Socket.IO advanced features (rooms, namespaces, adapters) build directly on the basics
- rt-06 — Socket.IO is one of the 'approaches' compared in rt-06; seeing the comparison motivates the library choice
- net-36-websocket