一、实时通信概述
大家好,欢迎来到《Node.js与WebSocket实现实时通信》的第一章。
说实话,我刚开始接触Web开发那会儿,对「实时」这个词的理解特别肤浅。以为页面能自动刷新就是实时了。后来踩了不少坑,才真正搞明白——实时通信,说白了就是让数据在产生的那一刻,立刻到达对方手里。不是几秒后,不是下次请求时,就是现在。
什么是实时通信
咱们先把这个概念说清楚。
传统的HTTP通信,就像你给朋友寄信。你写好信(发送请求),朋友收到后回信(返回响应)。一来一回,中间有延迟。而且朋友不会主动给你写信,除非你先寄过去。
实时通信不一样。它更像打电话——两边随时可以说话,延迟几乎感觉不到。服务器也能主动给客户端发消息,不需要客户端先问。
我个人的理解是:实时通信 = 低延迟 + 双向主动推送。这两个条件缺一不可。
核心特征:
- 延迟通常在毫秒级(几百毫秒以内)
- 服务端可以主动推送数据
- 连接建立后保持长连接状态
应用场景:你每天都在用
其实实时通信离我们很近。我随便举几个例子,你肯定都接触过。
在线聊天
微信、Slack、Discord,这些聊天工具的核心就是实时通信。你发一条消息,对方几乎同时收到。我记得有一次给朋友发「吃饭了吗」,他秒回「正在吃」——这种体验,靠HTTP轮询是做不到的。
协同编辑
Google Docs、飞书文档、Notion的多人协作功能。你在这边打字,同事那边实时看到变化。嗯,这里有个坑——协同编辑不只是传输文本,还要处理冲突。我曾经在一个项目里用WebSocket做协同编辑,结果两个人同时改同一段文字,数据乱成一锅粥。后来加了OT算法(操作转换)才搞定。
在线游戏
尤其是多人在线游戏,比如《王者荣耀》、《绝地求生》。每个玩家的位置、动作都要实时同步到其他玩家那里。延迟超过100ms,游戏体验就明显变差。我做过一个简单的联机贪吃蛇,用WebSocket同步蛇的位置,延迟控制在50ms以内,玩起来还算流畅。
股票行情
股票价格每秒都在变。你打开炒股软件,K线图实时跳动。这些数据就是通过实时通信推送到你屏幕上的。我有个朋友做量化交易,他说延迟多1毫秒,可能就少赚几万块——虽然夸张了点,但能看出实时性对金融场景有多重要。
| 场景 | 延迟要求 | 数据特点 |
|---|---|---|
| 在线聊天 | < 1秒 | 小数据量,频率中等 |
| 协同编辑 | < 200ms | 小数据量,频率高 |
| 在线游戏 | < 100ms | 数据量中等,频率极高 |
| 股票行情 | < 50ms | 小数据量,频率极高 |
技术选型:怎么选?
实现实时通信,有好几种技术方案。我按出现时间从早到晚给你捋一遍。
轮询(Polling)
这是最原始的方式。客户端每隔几秒发一次HTTP请求,问服务器「有新数据吗?」。服务器每次都得响应,哪怕没新数据也得回个「没有」。
你想想看,这效率多低。大部分请求都是白问的。而且延迟取决于轮询间隔——设成1秒,延迟最多1秒;设成100ms,服务器压力又扛不住。
避坑:我曾经在一个监控面板项目里用了轮询,每2秒请求一次。用户量一上来,服务器CPU直接飙到90%。后来换成WebSocket,CPU降到20%不到。轮询真的只适合小规模、低频率的场景。
长轮询(Long Polling)
轮询的改进版。客户端发请求后,服务器不立即返回,而是把请求「挂」在那里。等有新数据了,再返回响应。客户端收到后,立刻再发一个新请求。
说白了,就是让服务器「等一会儿再回答」。这样减少了大量无效请求。但问题也很明显——每次请求都要建立HTTP连接,开销还是不小。而且如果服务器挂了,客户端可能一直等不到响应。
SSE(Server-Sent Events)
SSE是HTML5标准的一部分。它允许服务器通过一个HTTP连接,持续向客户端推送数据。客户端只需要用EventSource接口监听就行。
// 客户端代码
const eventSource = new EventSource('/stream');
eventSource.onmessage = (event) => {
console.log('收到数据:', event.data);
};
SSE的优点是用起来简单,基于HTTP协议,兼容性好。但它是单向的——只能服务器推给客户端,客户端不能通过这个连接给服务器发数据。而且浏览器对SSE的连接数有限制(一般是6个)。
我的建议:如果你只需要服务器推送(比如股票行情、通知提醒),SSE是个不错的选择。但需要双向通信时,还是得用WebSocket。
WebSocket
终于说到主角了。WebSocket是HTML5提供的全双工通信协议。它通过一次HTTP握手,建立一条持久连接。之后客户端和服务器可以随时互相发数据,没有额外的HTTP开销。
WebSocket的延迟极低,通常在10ms以内。而且支持二进制数据,可以传图片、音频。我做过一个在线白板应用,用WebSocket同步画笔轨迹,延迟基本感觉不到。
| 技术 | 方向 | 延迟 | 开销 | 适用场景 |
|---|---|---|---|---|
| 轮询 | 单向(客户端主动) | 高(取决于间隔) | 高(大量无效请求) | 低频率、小规模 |
| 长轮询 | 单向(客户端主动) | 中等 | 中等 | 中等频率 |
| SSE | 单向(服务器推送) | 低 | 低 | 服务器推送场景 |
| WebSocket | 双向 | 极低 | 极低 | 实时双向通信 |
怎么选?我的一点经验
说实话,没有银弹。选哪种技术,得看你的具体需求。
- 简单通知、状态更新:SSE就够了,别杀鸡用牛刀。
- 聊天、游戏、协同编辑:必须WebSocket,双向通信是刚需。
- 临时方案、小项目:长轮询也能凑合用,但别指望它撑起大流量。
- 老项目改造:如果浏览器兼容性要求高(比如要支持IE),轮询或长轮询可能是唯一选择。
我个人习惯是:新项目一律用WebSocket。原因很简单——它是最通用的方案,能覆盖绝大多数实时场景。而且Node.js对WebSocket的支持非常好,后面几章我会带你一步步实现。
好了,第一章就到这里。下一章我们开始动手,用Node.js搭建一个WebSocket服务。到时候你会看到,代码其实没你想的那么复杂。