跳到主要内容

WebSocket 与其他实时技术对比

在构建实时 Web 应用时,开发者面临多种技术选择。本章对比 WebSocket 与其他常见的实时通信技术,帮助你根据实际需求做出合适的选择。

WebSocket vs Server-Sent Events (SSE)

Server-Sent Events(SSE)是一种基于 HTTP 的服务器推送技术,允许服务器向客户端发送单向事件流。它和 WebSocket 是实时通信领域最常见的两种选择。

核心差异

特性WebSocketSSE
通信方向双向(全双工)单向(服务器到客户端)
协议WebSocket(ws:// 或 wss://)HTTP(基于 text/event-stream)
自动重连需要手动实现浏览器内置支持
连接限制无浏览器限制HTTP/1.1 下每域名 6 个
数据类型文本和二进制仅文本(UTF-8)
消息帧需要自行实现内置消息 ID 和事件类型
HTTP/2 支持不受益完全支持多路复用
浏览器支持99%+97%+
复杂度中等较低

WebSocket 适用场景

WebSocket 提供真正的全双工通信,适合需要客户端和服务器频繁交互的场景:

即时通讯:聊天应用需要双方都能主动发送消息。

// WebSocket 聊天
const ws = new WebSocket('wss://chat.example.com');

ws.onmessage = (event) => {
const message = JSON.parse(event.data);
displayMessage(message);
};

// 客户端可以随时发送消息
function sendMessage(text) {
ws.send(JSON.stringify({
type: 'message',
content: text,
timestamp: Date.now()
}));
}

协作编辑:在线文档、白板等需要实时同步多方操作。

在线游戏:多人游戏需要低延迟的双向通信。

远程控制:需要实时发送控制指令并接收反馈。

SSE 适用场景

SSE 更简单,适合只需要服务器推送的场景:

实时通知:新闻推送、系统通知、社交动态。

// SSE 接收通知
const eventSource = new EventSource('/api/notifications');

eventSource.onmessage = (event) => {
const notification = JSON.parse(event.data);
showNotification(notification);
};

// 支持命名事件
eventSource.addEventListener('alert', (event) => {
showAlert(JSON.parse(event.data));
});

实时监控:服务器状态、股票行情、日志流。

进度更新:文件上传进度、任务执行状态。

AI 流式输出:LLM token 流式生成。

SSE 服务端实现

SSE 使用标准 HTTP 响应,实现非常简单:

// Node.js Express SSE
app.get('/events', (req, res) => {
res.writeHead(200, {
'Content-Type': 'text/event-stream',
'Cache-Control': 'no-cache',
'Connection': 'keep-alive'
});

// 发送数据
const sendEvent = (data) => {
res.write(`data: ${JSON.stringify(data)}\n\n`);
};

// 发送命名事件
const sendNamedEvent = (event, data) => {
res.write(`event: ${event}\n`);
res.write(`data: ${JSON.stringify(data)}\n\n`);
};

// 发送带 ID 的消息(用于断线重连恢复)
const sendWithId = (id, data) => {
res.write(`id: ${id}\n`);
res.write(`data: ${JSON.stringify(data)}\n\n`);
};

// 心跳保持连接
const heartbeat = setInterval(() => {
res.write(': heartbeat\n\n');
}, 30000);

// 清理
req.on('close', () => {
clearInterval(heartbeat);
});
});

SSE 断线重连机制

SSE 的自动重连是其重要优势:

const eventSource = new EventSource('/events');

// 浏览器自动重连,并带上 Last-Event-ID 头部
// 服务器可以根据此 ID 恢复消息流

eventSource.onerror = (event) => {
if (event.target.readyState === EventSource.CLOSED) {
console.log('连接已关闭');
} else if (event.target.readyState === EventSource.CONNECTING) {
console.log('正在重连...');
}
};

服务器可以通过发送 retry 字段设置重连间隔:

retry: 5000
data: 连接已建立

混合使用

在实际项目中,可以同时使用两种技术:

// SSE 用于服务器广播
const broadcasts = new EventSource('/api/broadcasts');
broadcasts.onmessage = (e) => {
showNotification(e.data);
};

// WebSocket 用于交互功能
const chat = new WebSocket('wss://api.example.com/chat');
chat.onmessage = (event) => {
displayMessage(JSON.parse(event.data));
};

// HTTP 用于常规 API 请求
async function updateProfile(data) {
await fetch('/api/profile', {
method: 'PUT',
body: JSON.stringify(data)
});
}

WebSocket vs HTTP 长轮询

长轮询是 WebSocket 普及之前常用的实时通信方案。

工作原理对比

HTTP 长轮询

WebSocket

性能对比

指标HTTP 长轮询WebSocket
连接开销每次请求重新建立一次握手后保持
延迟较高(每次请求往返)较低(持久连接)
服务器资源较高(频繁创建连接)较低
带宽消耗较高(重复的 HTTP 头)较低(轻量帧头)
实时性取决于轮询间隔真正实时
浏览器支持所有浏览器现代浏览器

长轮询示例

// 客户端长轮询
async function longPoll() {
try {
const response = await fetch('/api/poll?lastId=' + lastMessageId);
const messages = await response.json();

messages.forEach(msg => {
displayMessage(msg);
lastMessageId = msg.id;
});

// 立即发起下一次请求
longPoll();

} catch (error) {
// 出错后延迟重试
setTimeout(longPoll, 5000);
}
}

longPoll();

长轮询的主要问题是:

  • 每次请求都带有完整的 HTTP 头部
  • 服务器需要维护大量等待中的请求
  • 消息传递延迟取决于轮询间隔

WebSocket vs WebRTC

WebRTC 主要用于浏览器之间的点对点通信,与 WebSocket 的定位不同。

应用场景对比

场景WebSocketWebRTC
客户端-服务器通信完美适合不适合
浏览器间通信需要服务器中转直接 P2P
音视频传输需要自己实现编解码内置支持
文件传输适合小文件适合大文件 P2P
游戏适合需要服务器的游戏适合 P2P 游戏

协作关系

WebSocket 和 WebRTC 经常配合使用:

// WebSocket 用于信令交换
const signaling = new WebSocket('wss://signaling.example.com');

signaling.onmessage = async (event) => {
const data = JSON.parse(event.data);

switch (data.type) {
case 'offer':
// 收到 WebRTC offer
const pc = new RTCPeerConnection();
await pc.setRemoteDescription(data.offer);
const answer = await pc.createAnswer();
await pc.setLocalDescription(answer);

signaling.send(JSON.stringify({
type: 'answer',
answer: answer
}));
break;

case 'candidate':
// 收到 ICE candidate
await pc.addIceCandidate(data.candidate);
break;
}
};

WebSocket 负责信令交换,WebRTC 负责实际的媒体和数据传输。

WebSocket vs WebTransport

WebTransport 是新一代的浏览器传输 API,基于 HTTP/3。

WebTransport 特点

WebTransport 提供三种通信模式:

// 检查支持
if ('WebTransport' in window) {
const transport = new WebTransport('https://example.com/transport');

await transport.ready;

// 1. 数据报(不可靠,类似 UDP)
const datagram = transport.datagrams;
const writer = datagram.writable.getWriter();
await writer.write(new Uint8Array([1, 2, 3]));

// 2. 单向流
const stream = await transport.createUnidirectionalStream();
const streamWriter = stream.writable.getWriter();
await streamWriter.write(new Uint8Array([4, 5, 6]));

// 3. 双向流
const bidirectional = await transport.createBidirectionalStream();
// 可读可写
}

对比总结

特性WebSocketWebTransport
协议WebSocket (RFC 6455)HTTP/3
可靠性完全可靠可选可靠或不可靠
多路复用单一消息流(HTTP/2 下可多路复用)多个独立流
背压支持有限(WebSocketStream)原生支持
浏览器支持99%+较新浏览器
适用场景通用实时通信高性能、多流场景

WebTransport 更适合需要多个独立数据流、对延迟敏感的应用,如游戏和直播。

WebSocket 与 HTTP/2/HTTP/3 的演进

WebSocket 协议也在不断演进以适应新的网络环境:

协议版本标准连接方式优势
WebSocket over HTTP/1.1RFC 6455独立 TCP 连接广泛支持,稳定可靠
WebSocket over HTTP/2RFC 8441HTTP/2 流与 HTTP 共享连接,多路复用
WebSocket over HTTP/3草案阶段HTTP/3 流更低的连接建立延迟

WebSocket over HTTP/2 的改进:RFC 8441 允许 WebSocket 在 HTTP/2 连接上运行,解决了传统 WebSocket 无法与 HTTP/2 共享连接的问题。当页面通过 HTTP/2 加载时,WebSocket 可以使用同一 TCP 连接,减少连接开销。

如何选择

决策流程

需要实时通信?
├── 只需服务器推送?
│ ├── 需要简单实现? → SSE
│ └── 需要二进制数据? → WebSocket

├── 需要双向通信?
│ ├── 需要浏览器间 P2P? → WebRTC (+ WebSocket 信令)
│ ├── 需要多个独立流? → WebTransport
│ └── 通用场景? → WebSocket

└── 消息频率低或不重要? → HTTP 轮询

场景推荐

应用场景推荐技术理由
聊天应用WebSocket需要双向实时通信
股票行情SSE 或 WebSocket单向推送,SSE 更简单
在线游戏WebSocket 或 WebTransport低延迟双向通信
实时通知SSE单向推送,自动重连
视频会议WebRTC + WebSocket音视频 P2P + 信令
协作编辑WebSocket双向实时同步
日志流SSE单向流式输出
AI 流式输出SSE 或 WebSocket单向流,SSE 更常见

小结

选择实时通信技术时,需要考虑:

  1. 通信方向:单向推送选 SSE,双向通信选 WebSocket
  2. 数据类型:二进制数据必须用 WebSocket 或 WebTransport
  3. 可靠性需求:SSE 自动重连,WebSocket 需要手动实现
  4. 浏览器兼容:WebSocket 支持最广泛
  5. 性能需求:高性能场景考虑 WebTransport

实际项目中,多种技术可以共存,根据不同功能选择最合适的方案。例如,SSE 处理通知推送,WebSocket 处理聊天交互,HTTP 处理常规 API 请求。