WebSocket是浏览器原生全双工协议,Socket.io是其上层封装库;前者轻量低延迟但需手动处理连接与错误,后者支持自动降级、重连和房间管理,适合复杂业务场景。

WebSocket 是浏览器端唯一原生支持的全双工实时通信协议,Socket.io 则是在其基础上封装的兼容性更强、功能更丰富的库——但二者不是替代关系,而是分层协作:底层用 WebSocket 时最轻量、延迟最低;用 Socket.io 时能自动降级、自带重连和房间管理,适合业务复杂、客户端环境不可控的场景。
直接使用原生 WebSocket 连接服务端
适用于对延迟敏感、服务端已稳定支持 ws:// 协议、且不需要自动重连或广播等高级功能的场景。注意:WebSocket 构造函数只接受字符串 URL,不支持传入配置对象;连接状态需手动监听,错误无法自动恢复。
-
WebSocket实例创建后立即触发连接,不能“暂停”或“配置后再连” - 必须监听
onopen、onmessage、onerror、onclose四个事件,缺一不可 - 发送数据前必须确认
readyState === WebSocket.OPEN,否则会抛SyntaxError: Failed to execute 'send' on 'WebSocket': Still in CONNECTING state - 服务端地址必须是
ws://(开发)或wss://(生产),http://会静默失败
const socket = new WebSocket('ws://localhost:3000');
socket.onopen = () => {
console.log('Connected');
socket.send(JSON.stringify({ type: 'join', room: 'chat-123' }));
};
socket.onmessage = (event) => {
const data = JSON.parse(event.data);
console.log('Received:', data);
};
socket.onerror = (error) => {
console.error('WebSocket error:', error);
};
socket.onclose = () => {
console.log('Disconnected');
};
用 Socket.io 客户端连接并处理断线重连
Socket.io 默认启用自动重连,但默认参数在弱网下容易失效。关键点在于:重连逻辑由客户端控制,服务端无感知;重连期间未确认的消息会丢失,需业务层补发;reconnectionAttempts 和 timeout 必须显式设置才有效。
- 不传选项时,
io()会尝试连接/socket.io/路径,默认使用polling+websocket双传输 - 强制只用 WebSocket:传入
{ transports: ['websocket'] },但会失去 IE 等老浏览器兼容性 - 重连失败后不会自动清空事件监听器,重复调用
io()可能导致监听器叠加,建议复用实例 -
connect_error事件比error更可靠,后者可能在握手阶段就触发,而前者确保连接尝试已完成
const socket = io('http://localhost:3000', {
reconnection: true,
reconnectionAttempts: 5,
reconnectionDelay: 1000,
timeout: 20000,
transports: ['websocket', 'polling']
});
socket.on('connect', () => {
console.log('Connected with id:', socket.id);
});
socket.on('connect_error', (err) => {
console.error('Connection failed:', err.message);
});
socket.on('disconnect', (reason) => {
console.log('Disconnected:', reason); // 'io server disconnect', 'transport close', etc.
});
区分 Socket.io 的 event emit 与 broadcast 行为
emit 是向目标 socket 发送消息,broadcast 是向“除自己外的所有同命名空间 socket”发送——但这个“所有”受作用域限制。常见误区是以为 broadcast 天然跨房间,其实它默认只在当前命名空间内广播,且不进房间(to(room) 才进)。
立即学习“Java免费学习笔记(深入)”;
-
socket.emit('msg', data):仅自己收到 -
socket.broadcast.emit('msg', data):同命名空间内其他所有 socket 收到(不含自己) -
io.to('room-1').emit('msg', data):指定房间内所有 socket(含自己)收到 -
socket.to('room-1').emit('msg', data):指定房间内其他成员(不含自己)收到 - 房间名必须是字符串,不能是变量名或数字,否则
to()无效且无报错
// 服务端示例(Node.js + socket.io)
socket.join('lobby');
socket.to('lobby').emit('user_joined', { id: socket.id });
// 客户端监听
socket.on('user_joined', (data) => {
console.log('Someone joined lobby:', data.id);
});
真正难的是状态同步:WebSocket 没有内置消息确认机制,Socket.io 的 ack 回调只保证送达服务端,不保证业务逻辑执行成功。如果需要端到端可靠投递,得自己加序列号、重传和去重——这已经超出通信层范畴,属于应用协议设计了。










