[Node.js] WebSocket基础知识

实时场景的旧处理方案

考虑网页中的以下场景:

  • 股票K线图
  • 聊天
  • 警报、重要通知
  • 余座
  • 抢购页面的库存
  • ......

上述场景有一个共同特点——实时性

这种对实时性有要求的页面,会带来一些问题

比如下面的聊天场景

image-20250405132334026

由于HTTP协议是请求-响应模式,请求必须在前,响应必须在后,这就导致了服务器无法「主动」的把消息告诉客户端。

开发者想了很多办法来解决这一问题

当然终极解决方案自然是WebSocket,但了解过去的一些做法、参观前辈们经历的痛苦还是有益的。

短轮询

short polling,中文翻译为短轮询,是一种「话痨式」的方式。

客户端每隔一小段时间就向服务器请求一次,询问有没有新消息

sequenceDiagram 客户端->>服务器: 有新消息吗? 服务器->>客户端: 没 Note over 客户端,服务器: 一段时间后... 客户端->>服务器: 有新消息吗? 服务器->>客户端: 没 Note over 客户端,服务器: 一段时间后... 客户端->>服务器: 有新消息吗? 服务器->>客户端: 有,user1对你说:你好 Note over 客户端,服务器: 一段时间后... 客户端->>服务器: 有新消息吗? 服务器->>客户端: 没 Note over 客户端,服务器: 一段时间后... 客户端->>服务器: 有新消息吗? 服务器->>客户端: 没

实现短轮询是非常简单的,客户端只需要设置一个计时器不断发送请求即可

这种方案的缺陷是非常明显的:

  • 会产生大量无意义的请求
  • 会频繁打开关闭连接
  • 实时性并不高

长轮询

我们的前辈在有限的条件下,充分发挥智慧,来解决短轮询的问题,于是演化为长轮询

sequenceDiagram 客户端->>+服务器: 有新消息吗? Note right of 服务器: 没有消息不会响应 Note right of 服务器: 一段时间后... 服务器->>-客户端: user1对你说:你好 客户端->>+服务器: 有新消息吗? Note right of 服务器: 没有消息不会响应 Note right of 服务器: 一段时间后... 服务器->>-客户端: user1对你说:你吃了没 客户端->>服务器: ......

长轮询有效的解决了「话痨问题」,让每一次请求和响应都是有意义的

但长轮询仍然存在问题:

  • 客户端长时间收不到响应会导致超时,从而主动断开和服务器的连接

    这种情况是可以处理的,让ajax请求因为超时而结束时,立即重新发送请求到服务器

    虽然这种做法会让之前的请求变得无意义,但毕竟比短轮询好多了

  • 由于客户端可能「过早的」请求了服务器,服务器不得不挂起这个请求直到新消息的出现。这会让服务器长时间的占用资源却没什么实际的事情可做。

WebSocket

伴随着HTML5出现的WebSocket,从协议上赋予了服务器主动推送消息的能力

image-20250405134734354

从上图可以看出:

  • WebSocket也是建立在TCP协议之上的,利用的是TCP全双工通信的能力

    • 单工模式:数据的流向是单向的,不能反向,类似于收音机
    • 半双工:同一时候数据只能单向传输(要么是发送,要么是接收),类似于对讲机
    • 全双工:同一时候可以双向传输,类似于打电话
  • 使用WebSocket,会经历两个阶段:握手阶段、通信阶段

虽然优于轮询方案,但WebSocket仍然是有缺点的:

  • 兼容性

    WebSocket是HTML5新增的内容,因此古董版本的浏览器并不支持

  • 维持TCP连接需要耗费资源

    对于那些消息量少的场景,维持TCP连接确实会造成资源的浪费

原生API

https://developer.mozilla.org/zh-CN/docs/Web/API/WebSocket/WebSocket

const ws = new WebSocket("websocket服务器地址"); // 创建一个 websocket 连接

// 事件:
// 握手完成后会触发
ws.onopen = function(){}
// 收到服务器消息的时候会触发
ws.onmessage = function(){}
// 连接关闭之后会触发
ws.onclose = function(){}

// 方法:
ws.send(消息); // 向 websocket 服务器发送消息

// 属性:
ws.readyState // 连接状态 0-正在连接中 1-已连接 2-正在关闭中 3-已关闭

Socket.io

官网:https://socket.io/

原生的接口虽然简单,但是在实际应用中会造成很多麻烦

比如一个页面,既有K线,也有实时聊天,于是:

image-20250405133419271

上图是一段时间中服务器给客户端推送的数据,你能区分这些数据都是什么意思吗?

这就是问题所在:连接双方可以在任何时候发送任何类型的数据,另一方必须要清楚这个数据的含义是什么

回忆HTTP是如何处理这个问题的

你会如何解决这个问题

虽然我们可以自行解决这些问题,但毕竟麻烦

Socket.io 帮助我们解决了这些问题,它把消息放到不同的事件中,通过监听和触发事件来实现对不同消息的处理

image-20250405133335456

客户端和服务器双方事先约定好不同的事件(这些事件全部都是自定义事件),事件由谁监听,由谁触发,就可以把各种消息进行有序管理了。


-EOF-

posted @ 2026-04-01 13:46  Zhentiw  阅读(2)  评论(0)    收藏  举报