web-realtime-socket-io
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseSocket.IO Real-Time Communication Patterns
Socket.IO 实时通信模式
Quick Guide: Use Socket.IO for real-time bidirectional communication when you need rooms, namespaces, automatic reconnection, acknowledgments, or transport fallback. Socket.IO is NOT a WebSocket implementation - it adds a protocol layer with additional features. Always define typed event interfaces, use theoption for tokens (never query strings), and clean up listeners on unmount.auth
<critical_requirements>
快速指南: 当你需要房间、命名空间、自动重连、消息确认或传输降级功能时,可使用 Socket.IO 实现实时双向通信。Socket.IO 并非 WebSocket 的实现——它在协议层之上添加了额外功能。始终定义类型化事件接口,使用选项传递令牌(绝不要用查询字符串),并在组件卸载时清理监听器。auth
<critical_requirements>
CRITICAL: Before Using This Skill
重要提示:使用此技能前须知
All code must follow project conventions in CLAUDE.md (kebab-case, named exports, import ordering,, named constants)import type
(You MUST define typed interfaces for ALL Socket.IO events - ServerToClientEvents and ClientToServerEvents)
(You MUST use the option for authentication tokens - NEVER pass tokens in query strings)
auth(You MUST clean up event listeners on component unmount using socket.off())
(You MUST handle connection errors and implement proper reconnection state management)
(You MUST use named constants for all timeout values, retry limits, and intervals)
</critical_requirements>
Auto-detection: Socket.IO, socket.io-client, io(), useSocket, socket.emit, socket.on, rooms, namespaces, acknowledgments, real-time
When to use:
- Building real-time features requiring rooms or namespaces (chat, multiplayer)
- Need automatic reconnection with connection state recovery
- Need acknowledgments/callbacks for message delivery confirmation
- Building applications that must work in restrictive network environments (fallback transports)
- Need server-side broadcasting patterns (emit to room, namespace, all clients)
Key patterns covered:
- TypeScript event interfaces (ServerToClientEvents, ClientToServerEvents)
- Client connection configuration and lifecycle
- Authentication via auth option and middleware
- Rooms and namespaces for logical grouping
- Acknowledgments and callbacks
- Connection state recovery (v4.6.0+)
- React integration hooks
When NOT to use:
- Simple WebSocket needs without rooms/namespaces (use native WebSocket)
- Need to connect to non-Socket.IO WebSocket servers (incompatible protocols)
- Minimal bundle size is critical (Socket.IO adds ~14.5KB gzipped overhead)
Detailed Resources:
- examples/core.md - Socket factory, React hooks, event listeners, message queue, typing indicators, volatile events, namespace multiplexing
- examples/authentication.md - Token auth, cookie auth, token refresh, namespace auth, auth state machine
- examples/rooms.md - Room manager, room hooks, multi-room chat, namespace sockets, conditional namespace access
- reference.md - Decision frameworks, client options reference, checklists
<philosophy>
所有代码必须遵循 CLAUDE.md 中的项目约定(短横线命名、命名导出、导入顺序、、命名常量)import type
(你必须为所有 Socket.IO 事件定义类型化接口——ServerToClientEvents 和 ClientToServerEvents)
(你必须使用 选项传递身份验证令牌——绝不要在查询字符串中传递令牌)
auth(你必须在组件卸载时使用 socket.off() 清理事件监听器)
(你必须处理连接错误并实现适当的重连状态管理)
(你必须为所有超时值、重试限制和时间间隔使用命名常量)
</critical_requirements>
自动检测: Socket.IO、socket.io-client、io()、useSocket、socket.emit、socket.on、rooms、namespaces、acknowledgments、real-time
适用场景:
- 构建需要房间或命名空间的实时功能(聊天、多人游戏)
- 需要带连接状态恢复的自动重连功能
- 需要消息传递确认的回调机制
- 构建必须在受限网络环境下运行的应用(传输降级)
- 需要服务器端广播模式(向房间、命名空间、所有客户端发送消息)
涵盖的核心模式:
- TypeScript 事件接口(ServerToClientEvents、ClientToServerEvents)
- 客户端连接配置与生命周期
- 通过 auth 选项和中间件实现身份验证
- 用于逻辑分组的房间与命名空间
- 消息确认与回调
- 连接状态恢复(v4.6.0+)
- React 集成钩子
不适用场景:
- 无需房间/命名空间的简单 WebSocket 需求(使用原生 WebSocket)
- 需要连接非 Socket.IO 的 WebSocket 服务器(协议不兼容)
- 对包体积有严格要求(Socket.IO 压缩后约增加 14.5KB 开销)
详细资源:
- examples/core.md - Socket 工厂、React 钩子、事件监听器、消息队列、输入指示器、volatile 事件、命名空间多路复用
- examples/authentication.md - 令牌验证、Cookie 验证、令牌刷新、命名空间验证、验证状态机
- examples/rooms.md - 房间管理器、房间钩子、多房间聊天、命名空间套接字、条件命名空间访问
- reference.md - 决策框架、客户端选项参考、检查清单
<philosophy>
Philosophy
设计理念
Socket.IO provides a layer on top of WebSocket with additional features: automatic reconnection, room-based broadcasting, acknowledgments, and transport fallback. It is NOT a WebSocket implementation - a plain WebSocket client cannot connect to a Socket.IO server and vice versa.
Key Architectural Concepts:
-
Transport Abstraction: Socket.IO uses WebSocket when available but falls back to HTTP long-polling for restrictive networks. Default order: polling first, then upgrade to WebSocket.
-
Rooms: Server-side grouping mechanism for targeted broadcasting. Clients don't know about rooms - they're purely a server concept for organizing sockets.
-
Namespaces: Separate communication channels on the same connection. Used to separate concerns (e.g.,,
/chat,/admin). Each can have its own middleware./notifications -
Connection State Recovery (v4.6.0+): Missed events can be automatically delivered after brief disconnections, reducing manual state sync. Server-configurable with 2-minute default window.
Connection Lifecycle:
CONNECTING -> CONNECTED <-> (events) -> DISCONNECTING -> DISCONNECTED
| |
(error) <- reconnect <- (disconnect)Socket.IO vs Native WebSocket:
| Feature | Socket.IO | Native WebSocket |
|---|---|---|
| Transport fallback | Automatic | Manual |
| Reconnection | Built-in | Manual |
| Rooms | Built-in | Manual (server-side) |
| Namespaces | Built-in | Not available |
| Acknowledgments | Built-in | Manual |
| Protocol | Custom (incompatible) | Standard WebSocket |
| Bundle size | ~14.5KB gzipped | Native (0KB) |
<patterns>
Socket.IO 在 WebSocket 之上提供了一层额外功能:自动重连、基于房间的广播、消息确认和传输降级。它并非 WebSocket 的实现——原生 WebSocket 客户端无法连接到 Socket.IO 服务器,反之亦然。
核心架构概念:
-
传输抽象: Socket.IO 在可用时使用 WebSocket,但在受限网络环境下会降级为 HTTP 长轮询。默认顺序:先轮询,再升级到 WebSocket。
-
房间: 服务器端的分组机制,用于定向广播。客户端不知道房间的存在——房间纯粹是服务器端用于组织套接字的概念。
-
命名空间: 同一连接上的独立通信通道。用于分离不同业务逻辑(如、
/chat、/admin)。每个命名空间可拥有自己的中间件。/notifications -
连接状态恢复(v4.6.0+): 短暂断开连接后,可自动传递错过的事件,减少手动状态同步。服务器可配置,默认窗口为 2 分钟。
连接生命周期:
CONNECTING -> CONNECTED <-> (events) -> DISCONNECTING -> DISCONNECTED
| |
(error) <- reconnect <- (disconnect)Socket.IO vs 原生 WebSocket:
| 特性 | Socket.IO | 原生 WebSocket |
|---|---|---|
| 传输降级 | 自动 | 手动 |
| 重连机制 | 内置 | 手动 |
| 房间功能 | 内置 | 手动(服务器端实现) |
| 命名空间 | 内置 | 无 |
| 消息确认 | 内置 | 手动 |
| 协议 | 自定义(不兼容) | 标准 WebSocket |
| 包体积 | 约 14.5KB(压缩后) | 原生(0KB) |
<patterns>
Core Patterns
核心模式
Pattern 1: TypeScript Event Interfaces
模式 1:TypeScript 事件接口
Define separate interfaces for each communication direction. Socket.IO v4 enforces these at compile time.
typescript
interface ServerToClientEvents {
"message:received": (message: ChatMessage) => void;
"user:joined": (user: User) => void;
error: (error: SocketError) => void;
}
interface ClientToServerEvents {
"message:send": (
content: string,
callback: (res: MessageResponse) => void,
) => void;
"room:join": (roomId: string, callback: (result: JoinResult) => void) => void;
}
type TypedSocket = Socket<ServerToClientEvents, ClientToServerEvents>;Why this matters: Without typed events, typos in event names fail silently at runtime. Typed interfaces catch vs at compile time.
"mesage""message"See examples/core.md Example 1 for complete type definitions.
为每个通信方向定义独立的接口。Socket.IO v4 在编译时会强制执行这些类型。
typescript
interface ServerToClientEvents {
"message:received": (message: ChatMessage) => void;
"user:joined": (user: User) => void;
error: (error: SocketError) => void;
}
interface ClientToServerEvents {
"message:send": (
content: string,
callback: (res: MessageResponse) => void,
) => void;
"room:join": (roomId: string, callback: (result: JoinResult) => void) => void;
}
type TypedSocket = Socket<ServerToClientEvents, ClientToServerEvents>;重要性: 没有类型化事件的话,事件名称的拼写错误会在运行时静默失败。类型化接口可在编译时捕获类似 和 的错误。
"mesage""message"完整类型定义请参见 examples/core.md 示例 1。
Pattern 2: Client Configuration
模式 2:客户端配置
Token goes in object (never query string). Use named constants for all timing values. The option controls the connection timeout (default 20000ms). For acknowledgment timeouts, use (v4.6.0+) or .
authtimeoutackTimeoutsocket.timeout(ms).emitWithAck()typescript
const RECONNECTION_DELAY_MS = 1000;
const MAX_RECONNECTION_ATTEMPTS = 10;
const CONNECTION_TIMEOUT_MS = 20000;
const socket: TypedSocket = io(url, {
auth: { token }, // NOT in query string
reconnectionAttempts: MAX_RECONNECTION_ATTEMPTS,
reconnectionDelay: RECONNECTION_DELAY_MS,
timeout: CONNECTION_TIMEOUT_MS, // Connection timeout
transports: ["websocket", "polling"],
});Key distinction: = connection timeout. = per-emit acknowledgment timeout (requires option, v4.6.0+).
timeoutackTimeoutretriesSee examples/core.md Example 1 for full factory implementation.
令牌放在 对象中(绝不要用查询字符串)。所有计时值使用命名常量。 选项控制连接超时(默认 20000ms)。对于消息确认超时,使用 (v4.6.0+)或 。
authtimeoutackTimeoutsocket.timeout(ms).emitWithAck()typescript
const RECONNECTION_DELAY_MS = 1000;
const MAX_RECONNECTION_ATTEMPTS = 10;
const CONNECTION_TIMEOUT_MS = 20000;
const socket: TypedSocket = io(url, {
auth: { token }, // 不要放在查询字符串中
reconnectionAttempts: MAX_RECONNECTION_ATTEMPTS,
reconnectionDelay: RECONNECTION_DELAY_MS,
timeout: CONNECTION_TIMEOUT_MS, // 连接超时
transports: ["websocket", "polling"],
});关键区别: = 连接超时。 = 每次发送的消息确认超时(需要 选项,v4.6.0+)。
timeoutackTimeoutretries完整工厂实现请参见 examples/core.md 示例 1。
Pattern 3: Connection Lifecycle
模式 3:连接生命周期
Socket-level events (, , ) track the socket. Manager-level events (, , ) track the underlying connection. Always listen to both.
connectdisconnectconnect_errorreconnect_attemptreconnectreconnect_failedtypescript
socket.on("connect", () => {
/* connected */
});
socket.on("disconnect", (reason) => {
// socket.active === true means it will reconnect
});
socket.on("connect_error", (error) => {
/* handle */
});
// Manager-level: socket.io is the Manager instance
socket.io.on("reconnect_attempt", (attempt) => {
/* show UI */
});
socket.io.on("reconnect_failed", () => {
/* all attempts exhausted */
});Critical: Check (v4.6.0+) after to determine if missed events were automatically delivered or if you need a full state refresh.
socket.recoveredconnectSee examples/core.md Examples 2-3 for React hooks.
套接字级事件(、、)跟踪套接字状态。管理器级事件(、、)跟踪底层连接状态。务必同时监听这两类事件。
connectdisconnectconnect_errorreconnect_attemptreconnectreconnect_failedtypescript
socket.on("connect", () => {
/* 已连接 */
});
socket.on("disconnect", (reason) => {
// socket.active === true 表示将进行重连
});
socket.on("connect_error", (error) => {
/* 处理错误 */
});
// 管理器级:socket.io 是 Manager 实例
socket.io.on("reconnect_attempt", (attempt) => {
/* 更新 UI */
});
socket.io.on("reconnect_failed", () => {
/* 所有重试尝试已耗尽 */
});重要提示: 连接后检查 (v4.6.0+),以确定是否已自动传递错过的事件,或者是否需要完全刷新状态。
socket.recoveredReact 钩子实现请参见 examples/core.md 示例 2-3。
Pattern 4: Acknowledgments
模式 4:消息确认
Two approaches: automatic retries (v4.6.0+) or manual . Both confirm message delivery.
emitWithAcktypescript
// Automatic retries (v4.6.0+)
const socket = io(url, { ackTimeout: 5000, retries: 3 });
socket.emit("message:send", content, (response) => {
/* confirmed */
});
// Manual with emitWithAck
const response = await socket
.timeout(5000)
.emitWithAck("message:send", content);Gotcha: When using automatic retries, server handlers must be idempotent since the same packet may arrive multiple times.
See examples/core.md Example 4 for the emit hook pattern.
两种方式:自动重试(v4.6.0+)或手动 。两者均可确认消息已送达。
emitWithAcktypescript
// 自动重试(v4.6.0+)
const socket = io(url, { ackTimeout: 5000, retries: 3 });
socket.emit("message:send", content, (response) => {
/* 已确认 */
});
// 手动使用 emitWithAck
const response = await socket
.timeout(5000)
.emitWithAck("message:send", content);注意事项: 使用自动重试时,服务器处理程序必须是幂等的,因为同一数据包可能会多次到达。
发送钩子模式请参见 examples/core.md 示例 4。
Pattern 5: Auth Token Handling
模式 5:令牌验证处理
The option can be an object (evaluated once) or a function (called on every connection/reconnection). Use the function form to ensure fresh tokens on reconnect.
authtypescript
// Static (stale on reconnect)
const socket = io(url, { auth: { token } });
// Dynamic (fresh on every connection attempt)
const socket = io(url, {
auth: (cb) => {
cb({ token: getToken() });
},
});
// Or update before reconnection
socket.io.on("reconnect_attempt", () => {
socket.auth = { token: getToken() };
});See examples/authentication.md for full auth patterns, token refresh, and auth state machine.
authtypescript
// 静态(重连时令牌可能过期)
const socket = io(url, { auth: { token } });
// 动态(每次连接尝试时获取新鲜令牌)
const socket = io(url, {
auth: (cb) => {
cb({ token: getToken() });
},
});
// 或者在重连前更新
socket.io.on("reconnect_attempt", () => {
socket.auth = { token: getToken() };
});完整验证模式、令牌刷新和验证状态机请参见 examples/authentication.md。
Pattern 6: Rooms and Namespaces
模式 6:房间与命名空间
Rooms are server-side only - clients request to join, server decides. Namespaces are protocol-level - clients connect explicitly. Multiple namespace sockets share one underlying connection via the Manager.
typescript
// Namespaces: use Manager for connection sharing
const manager = new Manager(url, { autoConnect: false });
const chatSocket = manager.socket("/chat");
const adminSocket = manager.socket("/admin", {
auth: { token: adminToken }, // Per-namespace auth
});
manager.connect();See examples/rooms.md for room manager, room hooks, and namespace patterns.
房间仅存在于服务器端——客户端请求加入,服务器决定是否允许。命名空间是协议级别的——客户端显式连接。多个命名空间套接字通过 Manager 共享一个底层连接。
typescript
// 命名空间:使用 Manager 共享连接
const manager = new Manager(url, { autoConnect: false });
const chatSocket = manager.socket("/chat");
const adminSocket = manager.socket("/admin", {
auth: { token: adminToken }, // 每个命名空间独立验证
});
manager.connect();房间管理器、房间钩子和命名空间模式请参见 examples/rooms.md。
Pattern 7: Listener Cleanup
模式 7:监听器清理
Every must have a corresponding . In React, return cleanup from . Pass the exact same function reference to .
socket.on()socket.off()useEffectoff()typescript
useEffect(() => {
const handler = (msg: Message) => setMessages((prev) => [...prev, msg]);
socket.on("message", handler);
return () => {
socket.off("message", handler);
}; // Same reference
}, [socket]);Why this matters: Without cleanup, handlers accumulate on re-renders causing memory leaks and duplicate processing.
</patterns>
<red_flags>
每个 必须对应一个 。在 React 中,从 返回清理函数。传递给 的函数引用必须与 中完全相同。
socket.on()socket.off()useEffectoff()on()typescript
useEffect(() => {
const handler = (msg: Message) => setMessages((prev) => [...prev, msg]);
socket.on("message", handler);
return () => {
socket.off("message", handler);
}; // 相同的函数引用
}, [socket]);重要性: 如果不清理,处理程序会在重渲染时累积,导致内存泄漏和重复处理。
</patterns>
<red_flags>
RED FLAGS
注意事项(红色警告)
- Token in query string - Visible in server logs, browser history, proxy logs. Always use option.
auth - No event type definitions - Typos in event names fail silently. Define /
ServerToClientEvents.ClientToServerEvents - Missing socket.off() cleanup - Memory leaks and duplicate handlers accumulate.
- No connection error handling - Users see blank screens with no feedback on failures.
- Using socket.id as user identifier - Changes on every reconnection. Use server-provided user ID.
- Sending without connected check - on a disconnected socket fails silently. Check
socket.emit()or queue messages.socket.connected - Confusing with
timeout-ackTimeoutis connection timeout (default 20000ms).timeoutis acknowledgment timeout (v4.6.0+, requiresackTimeout).retries - Static auth with long sessions - Token expires, reconnection fails. Use as a function or update on
auth.reconnect_attempt
Gotchas:
- Socket.IO protocol is incompatible with plain WebSocket - they cannot interoperate
- Default transport order is polling-first, then upgrade to WebSocket (not WebSocket-first)
- only works when server has connection state recovery enabled (v4.6.0+)
socket.recovered - Namespaces share one WebSocket connection - a transport failure affects all namespaces
- Rooms are purely server-side - the client never knows which rooms it belongs to
- may silently drop messages - only use for expendable data (cursor positions)
volatile.emit()
</red_flags>
<critical_reminders>
- 令牌放在查询字符串中 - 会出现在服务器日志、浏览器历史和代理日志中。务必使用 选项。
auth - 未定义事件类型 - 事件名称拼写错误会静默失败。定义 /
ServerToClientEvents。ClientToServerEvents - 缺少 socket.off() 清理 - 内存泄漏和重复处理程序累积。
- 未处理连接错误 - 用户遇到失败时看不到任何反馈,仅显示空白页面。
- 使用 socket.id 作为用户标识符 - 每次重连都会变化。使用服务器提供的用户 ID。
- 未检查连接状态就发送消息 - 在断开连接的套接字上调用 会静默失败。检查
socket.emit()或对消息进行排队。socket.connected - 混淆 和
timeout-ackTimeout是连接超时(默认 20000ms)。timeout是消息确认超时(v4.6.0+,需要ackTimeout选项)。retries - 长会话使用静态验证 - 令牌过期后,重连会失败。使用函数形式的 或在
auth时更新令牌。reconnect_attempt
常见陷阱:
- Socket.IO 协议与原生 WebSocket 不兼容——它们无法互操作
- 默认传输顺序是先轮询,再升级到 WebSocket(并非优先使用 WebSocket)
- 仅在服务器启用连接状态恢复时生效(v4.6.0+)
socket.recovered - 命名空间共享一个 WebSocket 连接——传输失败会影响所有命名空间
- 房间纯粹是服务器端概念——客户端永远不知道自己属于哪些房间
- 可能会静默丢弃消息——仅用于可丢弃的数据(如光标位置)
volatile.emit()
</red_flags>
<critical_reminders>
CRITICAL REMINDERS
重要提醒
All code must follow project conventions in CLAUDE.md
(You MUST define typed interfaces for ALL Socket.IO events - ServerToClientEvents and ClientToServerEvents)
(You MUST use the option for authentication tokens - NEVER pass tokens in query strings)
auth(You MUST clean up event listeners on component unmount using socket.off())
(You MUST handle connection errors and implement proper reconnection state management)
(You MUST use named constants for all timeout values, retry limits, and intervals)
Failure to follow these rules will result in security vulnerabilities, memory leaks, and type-unsafe code.
</critical_reminders>
所有代码必须遵循 CLAUDE.md 中的项目约定
(你必须为所有 Socket.IO 事件定义类型化接口——ServerToClientEvents 和 ClientToServerEvents)
(你必须使用 选项传递身份验证令牌——绝不要在查询字符串中传递令牌)
auth(你必须在组件卸载时使用 socket.off() 清理事件监听器)
(你必须处理连接错误并实现适当的重连状态管理)
(你必须为所有超时值、重试限制和时间间隔使用命名常量)
不遵循这些规则会导致安全漏洞、内存泄漏和类型不安全的代码。
</critical_reminders>