
问题1.在线聊天为什么用websocket,这个是请求响应吗感觉不像,两个人聊天,两个人都是客户端?用轮训方式不行吗?websocket是解决服务器推送吧,每次一说到这个我第一反应行情展示,然后就没了,搞得我一直以为websocket只能实时行情展示用到。
问题2.
在聊天场景中,A 和 B 都是 WebSocket 客户端,他们同时连接到服务器。
● A 发消息给服务器。
● 服务器收到后,通过 WebSocket 连接主动推送给 B。
● B 看到消息,回复,服务器再推送给 A。
这里,服务器扮演的是一个“消息路由器/中转站”的角色。这个是对方在线再推送还是不在线也推送,怎么感知
WebSocket 确实不是传统的请求-响应模式,轮询方式在技术上也能实现聊天,但代价极大。你之所以把它和“实时行情”绑定,是因为行情展示是它最典型、最容易被感知的场景之一,但这绝对不是它唯一的用途。
我们来一层一层拆解你的疑惑:
1. WebSocket 是请求-响应模式吗?
不是。
传统的 HTTP 是“一问一答”的单向模式:客户端发请求,服务器给响应,然后连接断开(或者复用)。
WebSocket 是全双工通信。你可以把它想象成打电话,而不是发短信。一旦双方建立连接(握手),这条通道就一直敞开着。服务器可以随时主动给客户端发消息,客户端也可以随时发给服务器,互不干扰,不需要每次都重新发起请求。
2. 两个人聊天,两个人都是客户端?
完全正确!
在聊天场景中,A 和 B 都是 WebSocket 客户端,他们同时连接到服务器。
● A 发消息给服务器。
● 服务器收到后,通过 WebSocket 连接主动推送给 B。
● B 看到消息,回复,服务器再推送给 A。
这里,服务器扮演的是一个“消息路由器/中转站”的角色。
3. 用轮询(Polling)方式不行吗?
技术上可行,但现实中很“惨”。
轮询就是客户端每隔 1 秒问一次服务器:“有新消息吗?”
● 浪费带宽:99% 的请求服务器都会回答“没有”,白白消耗网络资源。
● 延迟高:如果轮询间隔是 3 秒,那消息最多会有 3 秒的延迟,聊天体验像“发微信卡了”。
● 服务器压力大:1 万个用户在线,每秒就要处理 1 万次 HTTP 请求,服务器很容易扛不住。
WebSocket 建立连接后,发一条消息只需要极小的数据头(几字节),延迟是毫秒级的,完美契合聊天需求。
4. 为什么你总觉得它只能做“行情展示”?
因为行情展示把 WebSocket 的特点放大到了极致:
● 数据更新极快:股票/加密货币价格每秒都在变。
● 纯服务端驱动:用户不需要点任何按钮,数据自己就蹦出来了。
● 多播/广播:同一个价格可以瞬间推送给几万个在线用户。
这种“服务器疯狂往客户端塞数据”的场景,让人对 WebSocket 印象深刻。
5. WebSocket 还能干嘛?(远不止行情和聊天)
其实你每天都在用,只是没意识到:
● 在线协作文档:腾讯文档、飞书文档里,你刚打一个字,同事那边立刻就出现了。这就是 WebSocket 在实时同步你的编辑操作。
● 游戏同步:王者荣耀、吃鸡游戏里,其他玩家的移动、开枪,都是服务器通过 WebSocket 实时推给你的。
● 弹幕系统:B站、抖音直播间的弹幕,几千人同时发,全靠 WebSocket 广播。
● 实时通知/告警:比如你在后台操作了一个耗时任务,完成后网页右上角自动弹出“处理成功”,不需要你手动刷新。
● IoT 物联网:智能手表、智能家居的状态实时上报和远程控制。
总结一下:
只要是需要“低延迟”和“服务器主动推送”的场景,WebSocket 都是首选。聊天只是其中一个非常经典的“双向高频”应用而已。你的思考方向完全是对的,只是被“行情展示”这个标签稍微局限了一下视野!
在真实的聊天场景中,服务器必须知道对方是否在线,因为这决定了消息是“直接推送”还是“离线存储”。
服务器感知用户在线状态,主要依赖以下两种机制:
1. 监听连接的建立与断开(基础感知)
WebSocket 本身是长连接,服务器可以通过监听连接的生命周期来感知状态:
● 上线感知:当用户打开聊天页面,客户端与服务器建立 WebSocket 连接时,服务器会触发 onOpen 或 connection 事件,此时服务器就知道该用户“上线”了,并将其加入在线用户列表。
● 下线感知:当用户正常退出页面或关闭浏览器时,连接断开,服务器触发 onClose 或 close 事件,此时将用户从在线列表中移除。
2. 心跳机制(解决“假在线”问题)
仅仅依靠连接断开事件是不够的。在复杂的网络环境中,如果用户设备突然断电、网络中断、或者切换网络(如 WiFi 切 4G),底层的 TCP 连接可能并不会立刻断开。此时连接实际已死,但服务器应用层仍误以为用户在线,这就造成了“假活着”现象。
为了解决这个问题,服务器和客户端需要配合实现心跳机制(Heartbeat):
● 定时问候:客户端会定期向服务器发送一条“我还活着吗?”的消息(Ping)。
● 确认存活:服务器收到后回复“你还活着”(Pong),并记录该用户最后一次活跃的时间戳。
● 超时判定:服务器端会启动定时任务,如果发现在设定的超时时间(例如 1 分钟)内,没有收到某个用户的任何心跳包,就会判定该用户已经异常掉线(下线),从而主动清理该连接并更新其状态。
服务器感知到状态后,是如何处理消息的?
基于上述机制,当 A 给 B 发消息时,服务器(作为消息路由器)的处理逻辑如下:
1. B 在线:服务器在内存中的在线列表(或共享状态存储如 Redis)里查到了 B 的有效连接,就会直接通过 WebSocket 将消息推送给 B。
2. B 不在线:如果服务器发现 B 不在在线列表中,或者 B 的连接已经超时失效,服务器就不会尝试推送,而是将这条消息写入数据库作为“离线消息”存储起来。等 B 下次上线(重新建立 WebSocket 连接)时,服务器再把离线消息一次性推给 B。
简单来说,服务器就像一个智能邮局:它不仅负责送信,还通过“心跳打卡”精准掌握每个人的行踪。人在就当面交,不在就放进信箱(数据库)等回来再交。
这个场景其实是我们日常办公中经常遇到,但可能没注意背后技术的例子。我用一个具体的场景给你还原一下:
场景还原:导出一个超大的报表
假设你在使用一个企业后台管理系统,你需要导出全公司一万名员工一整年的考勤数据。
1. 你发起请求:你点击了“导出”按钮。
2. 后台开始处理:服务器收到请求,开始疯狂查数据库、计算数据。这个过程非常耗时,可能需要整整 3 分钟。
3. 传统的痛点(没有 WebSocket):如果你用的是传统网页,这 3 分钟里你只能干等,或者疯狂点刷新按钮看“导出好了没”。如果页面不小心关了,你就彻底不知道任务到哪一步了。
4. WebSocket 的体验(实时通知):
- 你点击“导出”后,服务器告诉你:“收到,正在处理,你可以先去忙别的。”
- 此时,你的网页和服务器之间保持着一条 WebSocket 长连接。
- 3 分钟后,服务器终于把报表生成好了。此时,服务器通过这条长连接,主动给你的网页发了一条消息:“报表生成完毕!”
- 你的网页收到这条消息后,立刻在屏幕右上角弹出一个绿色的提示框:“✅ 考勤报表已生成,点击这里下载”。
为什么这必须是 WebSocket?
因为“任务完成”这个时间点,完全是由服务器决定的。
客户端(你的浏览器)并不知道服务器什么时候能算完,所以客户端没法主动去问(轮询太浪费资源)。只有当服务器算完的那一瞬间,主动推一条消息给客户端,才能实现这种“无缝衔接”的体验。
生活中类似的例子:
- 外卖/打车软件:你点了一份外卖,不需要一直刷新页面,骑手一接单、一取餐、一到达,手机屏幕就会自动弹出状态更新。
- 网盘上传:你往百度网盘传一个大文件,传完的瞬间,网页自动弹出“上传成功”。
- 游戏/系统更新:你挂着游戏等更新,进度条走到 100% 时,系统自动弹窗提示“更新完毕,请重启”。
一句话总结:
传统的 HTTP 像是你去餐厅点菜,你得一直问服务员“我的菜好了没?”;
而 WebSocket 像是餐厅装了叫号系统,菜一做好,系统直接“叮”一声主动喊你。这种“叮”的一声,就是实时通知/告警。