当前位置: 首页 > news >正文

WebSocket详解

一.什么是 WebSocket?

WebSocket 是一种在单个 TCP 连接上进行全双工(双向)通信的协议。它是为了弥补传统 HTTP 协议在实时通信场景中的不足而设计的,允许浏览器和服务器之间进行低延迟的实时数据传输

 二.WebSocket的优势

WebSocket 与 HTTP 的区别

特性WebSocketHTTP
协议类型双向通信协议请求-响应协议
连接状态持久连接每个请求都需要建立新连接
数据传输方式双向全双工通信客户端发起请求,服务器响应
连接开销低开销(连接一次即可)每个请求都需要建立新的连接
实时性实时,适合长时间的数据交换每次请求/响应有延迟,适合短期通信
适用场景实时聊天、在线游戏、推送通知静态网页加载、表单提交等

 

​​​​

我们再来看看与其他实时通讯技术的对比

通信方式描述优点缺点
轮询客户端以固定时间间隔(如每秒)向服务器发送 HTTP 请求,询问是否有新数据。每次请求都需要建立新连接。- 简单易实现- 延迟高:每次请求都需要建立新连接,延迟较大。
- 带宽浪费:频繁发送无效请求。
- 服务器负担大:每个请求都需要重新建立连接并处理。
长轮询 客户端向服务器发送请求,服务器保持连接,直到有新数据时才响应客户端。减少了连接的频繁建立。- 减少连接建立开销:相较于普通轮询,减少了频繁的连接请求。
- 更低的延迟:由于连接持续存在。
- 仍然存在延迟:客户端必须等待服务器推送新数据。
- 资源消耗大:等待响应之后再关闭,还是有重复连接
 SSE服务器单向推送数据到客户端,支持实时数据流,但只支持单向通信。- 实时推送:服务器可以随时推送数据给客户端。
- 实现简单:只需服务器推送数据。
- 单向通信:不支持客户端向服务器发送数据。
- 不适合双向实时应用:无法进行双向数据交互。
- 浏览器兼容性差:部分浏览器不完全支持 SSE。

  三.WebSocket的属性和方法

WebSocket 属性

属性描述示例
url连接的目标 URL。new WebSocket('wss://example.com');
readyState返回 WebSocket 连接的当前状态:0(连接中)、1(已连接)、2(关闭中)、3(已关闭)。console.log(socket.readyState);
bufferedAmount当前缓冲区中待发送的数据大小(字节)。console.log(socket.bufferedAmount);
protocol连接时使用的子协议(如果有)。console.log(socket.protocol);
extensions返回连接时使用的扩展协议(如果有)。console.log(socket.extensions);


WebSocket 方法

方法描述示例
send()向服务器发送消息(文本或二进制)。socket.send("Hello, Server!");
close()关闭 WebSocket 连接。socket.close();


WebSocket 事件

事件描述触发时机
onopen连接成功建立时触发。连接成功后触发
onmessage接收到服务器消息时触发。当服务器发送消息时触发
onclose连接关闭时触发。连接被关闭时触发
onerror发生错误时触发。连接发生错误时触发


WebSocket 连接状态常量(readyState

状态值描述
0 (CONNECTING)连接正在建立中。
1 (OPEN)连接已成功建立,可以进行数据交换。
2 (CLOSING)连接正在关闭。
3 (CLOSED)连接已关闭或无法建立连接。

 

 实例:

function webSocketManager(options) {if (!options.url) {throw new Error("url必传");}if (!options.bizMessageHandler) {throw new Error("bizMessageHandler必传");}this.url = options.url;this.heartbeatInterval = options.heartbeatInterval || 10; // 心跳间隔,单位:秒this.heartbeatStopCount = options.heartbeatStopCount || 3; // 心跳几次没响应就停止,默认3次this.autoReconnect = options.autoReconnect || true; // 断开后是否自动重连this.reconnectMinDuration = options.reconnectMinDuration || 10; // 重连最小间隔时间,单位:秒this.bizMessageHandler = options.bizMessageHandler; // 业务消息处理函数this.onConnectionOpen = options.onConnectionOpen; // 建立连接时回调
}webSocketManager.prototype.init = function() {this._connect();
};webSocketManager.prototype._startHeartbeat = function() {let _this = this;this._log("start heartbeat");this.lastSendSeq = 0; // 最后一次发出的序列号this.lastReceiveSeq = 0; // 最后一次收到的序列号this.webSocket.addEventListener("message", function(e) {let data = parseInt(e.data);if (!isNaN(data)) {_this.lastReceiveSeq = data;}});this.heartbeatTimerId = window.setInterval(function() {let noRespCount = _this.lastSendSeq - _this.lastReceiveSeq;if (noRespCount >= _this.heartbeatStopCount) {_this._log(`心跳包未响应超过${_this.heartbeatStopCount}次, 主动断开连接`);_this.webSocket.close();_this._stopHeartbeat();return;}_this.webSocket.send(_this.lastSendSeq++);}, this.heartbeatInterval * 1000);
};webSocketManager.prototype._stopHeartbeat = function() {if (null != this.heartbeatTimerId) {this._log("stop heartbeat");window.clearInterval(this.heartbeatTimerId);this.heartbeatTimerId = null;}
};// 连接建立
webSocketManager.prototype._connect = function() {let _this = this;this.webSocket = new WebSocket(this.url);this.connectTime = new Date().getTime();// 连接建立成功this.webSocket.onopen = function() {_this._log("onopen");if (_this.onConnectionOpen) {_this.onConnectionOpen();}_this._startHeartbeat();};// 连接建立失败this.webSocket.onerror = function() {_this._log("onerror");};// 连接断开this.webSocket.onclose = function() {_this._log("onclose");_this._stopHeartbeat();// 如果设置为自动重连就自动重连if (_this.autoReconnect) {// 为了避免断网时频繁不停重连的情况,需要判断下上次连接时间let duration = new Date().getTime() - _this.connectTime;// 如果重连小于最小间隔的时间,则延迟再重连,否则马上重连if (duration < _this.reconnectMinDuration * 1000) {setTimeout(function() {_this._connect();}, _this.reconnectMinDuration * 1000 - duration);} else {_this._connect();}}};this.webSocket.addEventListener("message", function(e) {let msg = e.data;// _this._log(`onmessage; message is ${msg}`);// 如果是业务消息则回调业务消息处理函数if (_this._isBizMessage(msg)) {_this.bizMessageHandler(msg);}});
};webSocketManager.prototype._isBizMessage = function(msg) {return msg && msg.indexOf("{") === 0;
};webSocketManager.prototype._log = function(msg) {if (console && console.log) {console.log(`[webSocketManager] ${new Date().getTime()} ${msg}`);}
};export default webSocketManager;

http://www.dtcms.com/a/298681.html

相关文章:

  • ClickHouse 高性能实时分析数据库-物化视图篇
  • 学习笔记《区块链技术与应用》第二天 共识机制
  • 亚马逊阿联酋推“Amazon Bazaar”:解码中东电商市场的本地化突围
  • 线程安全的单例模式
  • 基于米尔瑞芯微RK3576开发板部署运行TinyMaix:超轻量级推理框架
  • 2025年高防IP全景解读:从流量清洗到智能防御的核心跃迁
  • mib2c --生成标量数据对应c文件
  • NOIP普及组系列【2015】 P2669 [NOIP 2015 普及组] 金币题解
  • GPU 驱动安装升级测试
  • 避开算力坑!无人机桥梁检测场景下YOLO模型选型指南
  • Minio Docker 集群部署
  • 【阅读整理】野火ADC_AD7192模块资料
  • haproxy七层代理(超详细)
  • 算法讲解--查找总价值为目标值的两个商品
  • MyBatisPlus简介与基本CRUD
  • 域名服务器的作用是什么
  • 【js(7)创建对象的三种写法】
  • Node.js(三)之Express
  • Three.js 动画系统入门:Tween.js 与 AnimationMixer 的使用
  • 习题5.6 “数学黑洞“
  • Java研学-RabbitMQ(二)
  • 亚德诺半导体AD8612ARUZ-REEL双通道精密运算放大器,0.5μV超低失调电压+0.02μV/°C温漂!
  • 老龄化浪潮下的破局者:智慧养老重塑银发经济格局
  • ptmalloc(glibc-2.12.1)源码解析2
  • 深入理解 UDP 协议:从原理到实战的技术解析
  • 开源语音TTS与ASR大模型选型指南(2025最新版)(疯聊AI提供)
  • Paimon主键表的合并机制
  • 模糊综合评估法简单示例
  • MySQL的认识与基本操作
  • NaVILA源码解析——从其VLA部分到其low-level部分:涵盖legged-loco、rsl_rl