chat
主要实现方式
在实现即时通讯(IM)系统的前后端交互时,长轮询(Long Polling)、定时轮询(Polling)、SSE(Server-Sent Events)和 WebSocket(WS) 是常见的通信模式,但它们各有适用场景和优缺点。
以下是对比分析及现代 IM 系统的典型技术选型:
1. 通信模式对比
| 技术 | 协议 | 方向性 | 实时性 | 适用场景 | 缺点 | |——————–|———–|————–|————–|———————————-|———————————–| | 定时轮询 | HTTP | 客户端主动拉取 | 低(延迟高) | 简单场景,兼容性要求高 | 资源浪费(频繁请求)、延迟不可控 | | 长轮询 | HTTP | 客户端半主动 | 中(依赖超时) | 兼容老旧设备,短时实时需求 | 连接频繁重建,服务器并发压力大 | | SSE | HTTP | 服务端单向推送 | 高(单向流) | 服务端主动通知(如新闻推送) | 仅支持单向通信,需浏览器兼容性 | | WebSocket | WS/WSS | 全双工双向通信 | 高(实时) | 即时聊天、实时协作、游戏 | 需协议升级,部分网络设备可能拦截 |
2. IM 系统的技术选型实践
(1) WebSocket(首选方案)
- 核心优势:全双工通信、低延迟(毫秒级)、节省带宽(无 HTTP 头开销)。
- 典型应用:
- 实时消息收发(文字、指令)。
- 在线状态同步、输入状态感知。
- 音视频信令控制(如 WebRTC 的 SDP 交换)。
- 优化措施:
- 连接复用:通过单 WebSocket 通道承载多业务(如消息、心跳、状态更新)。
- 二进制协议:使用 Protobuf/FlatBuffers 替代 JSON 减少传输体积。
- 压缩与加密:开启 permessage-deflate 压缩,TLS 加密(WSS)。
(2) SSE(补充场景)
- 适用场景:
- 服务端单向推送(如系统公告、离线消息批量同步)。
- 客户端仅需接收数据(如 IM 中的“未读消息数”更新)。
- 优势:
- 浏览器原生支持(EventSource API),自动重连。
- 轻量级,适合文本数据流(如日志推送)。
(3) 长轮询(降级兼容)
- 使用场景:
- 兼容不支持 WebSocket 的环境(如旧版浏览器、某些企业防火墙限制)。
- 临时解决 WebSocket 连接被异常中断的问题。
- 实现要点:
- 服务端需维护挂起的请求队列,超时时间通常设为 30-60 秒。
- 结合 HTTP/2 多路复用减少连接开销。
(4) 定时轮询(不建议用于核心 IM)
- 仅适用于:
- 极低频消息场景(如每小时一次的天气推送)。
- 对实时性要求极低的遗留系统改造。
3. 现代 IM 系统的混合架构
实际场景中,WebSocket 为主 + SSE/长轮询降级 是主流方案:
- 主通道:WebSocket 用于实时消息、状态同步等核心功能。
- 降级策略:
- 当 WebSocket 连接失败时,自动切换至 SSE 或长轮询。
- 通过检测网络环境动态选择协议(如弱网下切到 QUIC over HTTP/3)。
- 补充通道:
- SSE 用于服务端单向推送(如系统通知)。
- HTTP 短连接用于非实时操作(如历史消息拉取、文件上传)。
4. 关键技术实现示例
(1) WebSocket 心跳保活
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16// 客户端心跳定时器
const heartbeatInterval = 30000; // 30秒
let heartbeatTimer;
ws.onopen = () => {
heartbeatTimer = setInterval(() => {
if (ws.readyState === WebSocket.OPEN) {
ws.send(JSON.stringify({ type: 'heartbeat' }));
}
}, heartbeatInterval);
};
ws.onclose = () => {
clearInterval(heartbeatTimer);
// 触发重连逻辑
};
(2) 服务端消息广播(WebSocket + Redis Pub/Sub)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27# Python 示例(使用 Tornado + Redis)
import tornado.websocket
import redis
class ChatHandler(tornado.websocket.WebSocketHandler):
clients = set()
def open(self):
self.clients.add(self)
# 订阅 Redis 频道
self.pubsub = redis.Redis().pubsub()
self.pubsub.subscribe('chat_channel')
tornado.ioloop.IOLoop.current().add_callback(self.listen_redis)
async def listen_redis(self):
while True:
message = await self.pubsub.get_message()
if message and message['type'] == 'message':
self.write_message(message['data'])
def on_message(self, message):
# 收到消息后发布到 Redis
redis.Redis().publish('chat_channel', message)
def on_close(self):
self.clients.remove(self)
self.pubsub.unsubscribe('chat_channel')
5. 选型建议
- 追求极致实时性:WebSocket + 二进制协议(如 Messenger、Slack)。
- 高兼容性要求:WebSocket 为主,长轮询/SSE 降级(如微信网页版)。
- 单向通知场景:SSE(如邮件到达提醒)。
- 物联网低功耗设备:MQTT over WebSocket(保留长连接优势,兼容 IoT 生态)。
总结
现代 IM 系统的核心交互以 WebSocket 为主,仅在特定场景或兼容性兜底时使用 SSE 或长轮询。设计时需关注:
- 连接稳定性:心跳机制、断线重连、多路复用。
- 协议效率:二进制压缩、减少冗余数据传输。
- 优雅降级:根据网络和设备能力动态切换通信模式。