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/长轮询降级 是主流方案:

  1. 主通道:WebSocket 用于实时消息、状态同步等核心功能。
  2. 降级策略
    • 当 WebSocket 连接失败时,自动切换至 SSE 或长轮询。
    • 通过检测网络环境动态选择协议(如弱网下切到 QUIC over HTTP/3)。
  3. 补充通道
    • SSE 用于服务端单向推送(如系统通知)。
    • HTTP 短连接用于非实时操作(如历史消息拉取、文件上传)。

4. 关键技术实现示例

(1) WebSocket 心跳保活

  [javascript]
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)

  [python]
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 或长轮询。设计时需关注:

  1. 连接稳定性:心跳机制、断线重连、多路复用。
  2. 协议效率:二进制压缩、减少冗余数据传输。
  3. 优雅降级:根据网络和设备能力动态切换通信模式。

总结

参考资料