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

WebSocket详解与封装工具类

一、前言

在我们了解websocket之前,不妨先想想这几个问题:

  1. websocket是什么?
  2. websocket有什么好处和特点?
  3. 为什么要用到websocket?
  4. 什么情况下会用到websocket?

好了,带着这几个疑问一起来了解一下websocket。

二、websocket简介

2.1 什么是websocket

WebSocket是HTML5开始提供的一种基于TCP的协议,用于在客户端和服务器之间建立持久连接,实现实时通讯的功能。

早期,客户端如果想实时拿到浏览器的最新数据就必须要通过发送http请求定时做轮询。每隔一段时间去向浏览器请求最新数据,这样大大的消耗了服务器的资源。

当使用了websocket与服务器建立连接,就不需要反复去轮询请求数据;当有最新消息时服务器会返回给客户端,而websocket可以立马监听到服务器的返回消息。

2.2 websocket的特点

2.2.1 优点
  1. 可以说实现连接的持久化,使客户端与服务器可以实时双向通讯;
  2. 减少了HTTP请求,大大减少了服务器的资源消耗,降低了网络负载;
  3. 没有同源限制,客户端可以与任意服务器通信;
  4. 协议标识符为ws,如果是加密的话就是wss;
2.2.2 缺点
  1. 有兼容问题,有一些老版本的浏览器不支持,同时有一些网络代理或防火墙会阻止连接;
  2. 缺乏安全策略,前面讲过没有同源策略的限制(这个需要注意);
  3. 对网络要求比较高,如果网络波动频繁可以回导致经常断联(导致断联原因不好排查);
  4. 需要保持长连接也会占用服务器的较多资源;
  5. 不适合大文件传输,websocket协议发送数据包不能超过2GB;

2.3 使用场景

websocket的主要优点就是保持客户端与服务端双向实时通讯,所以他主要的引用场景在于:

  1. 在线聊天室、游戏消息推送;
  2. 多媒体对话,例如视频会议等;
  3. 网页更新实时的数据流,股票价格波动、票房分析等;

三、websocket对象详解

WebSocket 对象提供了用于创建和管理 WebSocket]连接,以及可以通过该连接发送和接收数据的 API。

3.1 实例属性

通过使用WebSocket()构造函数来实例化一个WebSocket对象。

3.1.1 url

Websocket的绝对路径(只读)

3.1.2 readyState

WebSocket当前连接的状态(只读)

  1. WebSocket.CONNECTING:正在连接中
  2. WebSocket.OPEN:已经连接可以通信
  3. WebSocket.CLOSING:连接正在关闭
  4. WebSocket.CLOSED:连接已关闭或者没有连接成功
3.1.3 protocol

protocol是个只读属性,用于返回服务器端选中的子协议的名字;这是一个在创建 WebSocket对象时,在参数 protocols 中指定的字符串,当没有已建立的链接时为空串。

3.2 实例方法

3.2.1 close()

WebSocket.close() 方法关闭 WebSocket连接或连接尝试(如果有的话)。如果连接已经关闭,则此方法不执行任何操作。

3.2.2 send()

WebSocket.send() 方法将需要通过 WebSocket 链接传输至服务器的数据排入队列,并根据所需要传输的 data bytes 的大小来增加 bufferedAmount的值。若数据无法传输(例如数据需要缓存而缓冲区已满)时,套接字会自行关闭。

3.3 事件监听回调

3.3.1 close

监听将在 WebSocket 连接的readyState变为 CLOSED时被调用

3.3.2 error

websocket的连接由于一些错误事件的发生 (例如无法发送一些数据) 而被关闭时,一个error事件将被引发。

3.3.3 message

message 事件会在 WebSocket 接收到新消息时被触发。

3.3.4 open

监听将在 WebSocket 连接的readyState变为 CONNECTING时被调用

四、封装WebSocket工具函数

export class WebSocketClient {url = '';socket = null;// #计时器idheartbeatTimer = undefined;// 是否彻底关闭stopWebSocket = false;// 消息列表msgList = [];// 事件监听对象eventListenerInfo = {};// 构造函数constructor(url) {this.url = url;}// 添加事件监听addEventListener(type, listener) {if (!this.eventListenerInfo[type]) {this.eventListenerInfo[type] = [];}if (this.eventListenerInfo[type].indexOf(listener) === -1) {this.eventListenerInfo[type].push(listener);}}// 删除事件监听removeEventListener(type) {this.eventListenerInfo[type] = [];}// 监听事件绑定dispatchEvent(type, data) {const listenerArray = this.eventListenerInfo[type] || [];if (listenerArray.length === 0) return;listenerArray.forEach(listener => {listener.call(this, data);});}// 监听回调onopen(callBack) {this.addEventListener('open', callBack);}onmessage(callBack) {this.addEventListener('message', callBack);}onclose(callBack) {this.addEventListener('close', callBack);}onerror(callBack) {this.addEventListener('error', callBack);}// 消息列表增加addMsgList(list) {this.msgList = [...this.msgList, ...list];}// 批量发送消息pushMsgListAll() {if (this.msgList.length && this.socket && this.socket.readyState === WebSocket.OPEN) {// 发送头部数据const msg = this.msgList.shift();this.send(msg);pushMsgListAll();} else {// 重连重新发送this.connect();}}// 消息发送send(message) {if (this.socket && this.socket.readyState === WebSocket.OPEN) {this.socket.send(message);} else {console.error('websocket 未连接或已断开,请查看!');}}// 心跳检测onHeartbeat() {if (this.stopWebSocket) return;if (this.heartbeatTimer) {this.offHeartbeat();}this.heartbeatTimer = setInterval(() => {if (this.socket) {this.socket.send('ping,测试是否连接中');} else {console.error('websocket 未连接或已断开,请查看!');}}, 10000);}// 关闭心跳检测offHeartbeat() {clearInterval(this.heartbeatTimer);this.heartbeatTimer = undefined;}// 连接connect() {console.log(`WebSocket连接地址: ${this.url}`);if (this.socket && this.socket.readyState === WebSocket.OPEN) {return;}this.socket = new WebSocket(this.url);// !websocket连接成功this.socket.onopen = event => {this.stopWebSocket = false;// 开启心跳检测this.onHeartbeat();console.log(`连接成功`);// 判断是否有消息未发送成功if (this.msgList.length) {this.pushMsgListAll();}this.dispatchEvent('open', event);};this.socket.onmessage = event => {this.dispatchEvent('message', event);this.onHeartbeat();};this.socket.onclose = event => {if (!this.stopWebSocket) {// 断网重连逻辑setTimeout(() => {this.connect();}, 5000);}this.dispatchEvent('close', event);};this.socket.onerror = event => {this.offHeartbeat();this.dispatchEvent('error', event);};}// 关闭连接close() {if (this.socket) {this.stopWebSocket = true;this.socket.close();this.socket = null;this.removeEventListener('open');this.removeEventListener('message');this.removeEventListener('close');this.removeEventListener('error');}this.offHeartbeat();}
}

相关文章:

WebSocket详解与封装工具类

一、前言 在我们了解websocket之前,不妨先想想这几个问题: websocket是什么?websocket有什么好处和特点?为什么要用到websocket?什么情况下会用到websocket? 好了,带着这几个疑问一起来了解一…...

Linux学习, 进程和线程

进程 正在运行中的程序就是一个进程,进程有自己独有的内存空间和文件等等资源,进程中的资源一般都是相互隔离的。 进程内部还可以包含有多个线程,线程基本没有自己独占的资源(独有栈除外),他与进程内的其…...

SVM模型实现城镇居民月平均消费数据分类

SVM模型实现城镇居民月平均消费数据分类 一、SVM支持向量机简介二、数据集介绍三、SVM建模流程及分析一、SVM支持向量机简介 支持向量机是由感知机发展而来的机器学习算法,属于监督学习算法。支持向量机具有完备的理论基础,算法通过对样本进行求解,得到最大边距的超平面,并…...

[ZJCTF 2019]NiZhuanSiWei、[HUBUCTF 2022 新生赛]checkin、[SWPUCTF 2021 新生赛]pop

目录 [ZJCTF 2019]NiZhuanSiWei [HUBUCTF 2022 新生赛]checkin 1.PHP 关联数组 PHP 数组 | 菜鸟教程 2.PHP 弱比较绕过 PHP 类型比较 | 菜鸟教程 [SWPUCTF 2021 新生赛]pop [ZJCTF 2019]NiZhuanSiWei BUUCTF [ZJCTF 2019]NiZhuanSiWei特详解(php伪…...

c++“二纯” 纯虚函数和纯虚析构

首先给出这样一段概念: 在C中,当基类包含纯虚函数时,这些纯虚函数在基类中不需要(也不能)有定义。但是,如果基类有一个纯虚析构函数(即析构函数被声明为纯虚函数),那么情…...

MATLAB基础应用精讲-【数模应用】二元Logit分析(最终篇)(附python、MATLAB和R语言代码实现)

目录 算法原理 SPSSAU 1、二元logistic分析思路说明 2、如何使用SPSSAU进行二元logistic操作 3、二元logistic相关问题 算法流程 一、分析前准备 1、确定分析项 2.多重共线性判断 3.数据预处理 二、回归基本情况分析 三、模型拟合评价 1、似然比检验 2、拟合优…...

centos7安装mysql(完整)

官网5.7版本:https://cdn.mysql.com//Downloads/MySQL-5.7/mysql-5.7.29-1.el7.x86_64.rpm-bundle.tar 文件存于百度网盘:链接:https://pan.baidu.com/s/1x0fucIsD36_7agu88Jd2yg 提取码:s4m8 复制这段内容后打开百度网盘手机A…...

C++ STL std::vector的实现机制【面试】

std::vector 是 C 标准模板库(STL)中的一种序列容器,它封装了动态数组的实现,提供了一系列方法来操作这个动态数组。以下是 std::vector 的一些关键实现机制: 连续内存存储: std::vector 通过一块连续的内存…...

激活函数对比

激活函数 sigmoid / tanh / relu / leaky relu / elu / gelu / swish 1、sigmoid 优缺点 1) 均值!0,导致fwxb求导时,方向要么全正要么全负 可以通过batch批量训练来缓解 2) 输入值大于一定范围梯度就会消失 3) 运算复杂 2、tanh 优缺点 1) 均值0 2)…...

pycharm 上一次编辑位置不见了

目录 pycharm2024版 上一次编辑位置不见了,研究发现移到了左下角了,如下图所示: 上一次编辑位置快捷键: 设置为旧版ui,新版不好用 pycharm2024版 上一次编辑位置不见了,研究发现移到了左下角了&#xff…...

FFmpeg播放器的相关概念【1】

播放器框架 相关术语 •容器/文件(Conainer/File):即特定格式的多媒体文件,比如mp4、flv、mkv等。 • 媒体流(Stream):表示时间轴上的一段连续数据,如一段声音数据、一段…...

=与==的优先级

项目场景: 在写消息队列的过程中,问题代码如下: #include "message.h"void send(message *msg, int msg_id); void main() {printf("The sender process id %d\n", getpid());key_t key;int msg_id;message msg {.ty…...

在Linux上的Java项目导出PDF乱码问题

在Linux上的Java项目导出PDF乱码问题 场景:一个Java项目导出PDF,在我本地导出是没有问题,但是部署上Linux上后,导出就出现了乱码了。 处理方案 我这里使用的处理方案是在Linux服务器上安装一些PDF需要使用的字体 1.把字体上传到…...

java:使用shardingSphere访问mysql的分库分表数据

# 创建分库与分表 创建两个数据库【order_db_1、order_db_2】。 然后在两个数据库下分别创建三个表【orders_1、orders_2、orders_3】。 建表sql请参考: CREATE TABLE orders_1 (id bigint NOT NULL,order_type varchar(255) NULL DEFAULT NULL,customer_id bigi…...

红酒:如何选择适合的红酒储存容器

选择适合的红酒储存容器对于保持雷盛红酒的品质和风味至关重要。不同的容器具有不同的优缺点,因此应根据个人需求和条件进行选择。以下是一些常见的红酒储存容器的特点和适用场景: 玻璃瓶:玻璃瓶是常见的红酒储存容器。它具有良好的密封性能、…...

【C++】 使用CRT 库检测内存泄漏

CRT 库检测内存泄漏 一、CRT 库简介二、CRT 库的使用1、启用内存泄漏检测2、设置应用退出时显示内存泄漏报告3、丰富内存泄漏报告4、演示使用 内存泄漏是 C/C 应用程序中最微妙、最难以发现的 bug,存泄漏是由于之前分配的内存未能正确解除分配而导致的。 最开始的少…...

python手动搭建transformer,并实现自回归推理

以下是添加了详细注释的代码和参数介绍: Transformer 实现及自回归推理 本文展示了如何手动实现一个简化版的Transformer模型,并用自回归方式实现一个seq2seq任务,例如机器翻译。 导入必要的库 import torch import torch.nn as nn import…...

AI数据分析:用deepseek进行贡献度分析(帕累托法则)

帕累托法则,也称为80/20法则,是由意大利经济学家维尔弗雷多帕累托提出的。它指出在许多情况下,大约80%的效益来自于20%的原因。这个原则在很多领域都有应用,包括商业、经济、社会问题等。 在数据分析中,帕累托法则可以…...

生成式人工智能的风险与治理——以ChatGPT为例

文 | 西南政法大学经济法学院 马羽男 以ChatGPT为代表的生成式人工智能在创造社会福利的同时,也带来了诸多风险。因此,当务之急是结合我国生成式人工智能发展状况,厘清其应用价值与潜在风险之间的关系,以便在不影响应用发展的前提…...

十足正式在山东开疆拓土!首批店7月初开业,地区便利店现全新面貌!

十足便利店将正式进军山东市场,以济南、淄博两座城市为核心发展起点,目前济南市已经有三家十足门店正在装修施工中,首批15家门店将于7月初开业,这标志着十足集团市场战略布局迈出了至关重要的一步。 随着3月份罗森品牌在济南成功开…...

黑马Mybatis

Mybatis 表现层&#xff1a;页面展示 业务层&#xff1a;逻辑处理 持久层&#xff1a;持久数据化保存 在这里插入图片描述 Mybatis快速入门 ![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/6501c2109c4442118ceb6014725e48e4.png //logback.xml <?xml ver…...

令牌桶 滑动窗口->限流 分布式信号量->限并发的原理 lua脚本分析介绍

文章目录 前言限流限制并发的实际理解限流令牌桶代码实现结果分析令牌桶lua的模拟实现原理总结&#xff1a; 滑动窗口代码实现结果分析lua脚本原理解析 限并发分布式信号量代码实现结果分析lua脚本实现原理 双注解去实现限流 并发结果分析&#xff1a; 实际业务去理解体会统一注…...

聊一聊接口测试的意义有哪些?

目录 一、隔离性 & 早期测试 二、保障系统集成质量 三、验证业务逻辑的核心层 四、提升测试效率与覆盖度 五、系统稳定性的守护者 六、驱动团队协作与契约管理 七、性能与扩展性的前置评估 八、持续交付的核心支撑 接口测试的意义可以从四个维度展开&#xff0c;首…...

优选算法第十二讲:队列 + 宽搜 优先级队列

优选算法第十二讲&#xff1a;队列 宽搜 && 优先级队列 1.N叉树的层序遍历2.二叉树的锯齿型层序遍历3.二叉树最大宽度4.在每个树行中找最大值5.优先级队列 -- 最后一块石头的重量6.数据流中的第K大元素7.前K个高频单词8.数据流的中位数 1.N叉树的层序遍历 2.二叉树的锯…...

均衡后的SNRSINR

本文主要摘自参考文献中的前两篇&#xff0c;相关文献中经常会出现MIMO检测后的SINR不过一直没有找到相关数学推到过程&#xff0c;其中文献[1]中给出了相关原理在此仅做记录。 1. 系统模型 复信道模型 n t n_t nt​ 根发送天线&#xff0c; n r n_r nr​ 根接收天线的 MIMO 系…...

浪潮交换机配置track检测实现高速公路收费网络主备切换NQA

浪潮交换机track配置 项目背景高速网络拓扑网络情况分析通信线路收费网络路由 收费汇聚交换机相应配置收费汇聚track配置 项目背景 在实施省内一条高速公路时遇到的需求&#xff0c;本次涉及的主要是收费汇聚交换机的配置&#xff0c;浪潮网络设备在高速项目很少&#xff0c;通…...

c++第七天 继承与派生2

这一篇文章主要内容是 派生类构造函数与析构函数 在派生类中重写基类成员 以及多继承 第一部分&#xff1a;派生类构造函数与析构函数 当创建一个派生类对象时&#xff0c;基类成员是如何初始化的&#xff1f; 1.当派生类对象创建的时候&#xff0c;基类成员的初始化顺序 …...

拟合问题处理

在机器学习中&#xff0c;核心任务通常围绕模型训练和性能提升展开&#xff0c;但你提到的 “优化训练数据解决过拟合” 和 “提升泛化性能解决欠拟合” 需要结合更准确的概念进行梳理。以下是对机器学习核心任务的系统复习和修正&#xff1a; 一、机器学习的核心任务框架 机…...

ZYNQ学习记录FPGA(二)Verilog语言

一、Verilog简介 1.1 HDL&#xff08;Hardware Description language&#xff09; 在解释HDL之前&#xff0c;先来了解一下数字系统设计的流程&#xff1a;逻辑设计 -> 电路实现 -> 系统验证。 逻辑设计又称前端&#xff0c;在这个过程中就需要用到HDL&#xff0c;正文…...

用js实现常见排序算法

以下是几种常见排序算法的 JS实现&#xff0c;包括选择排序、冒泡排序、插入排序、快速排序和归并排序&#xff0c;以及每种算法的特点和复杂度分析 1. 选择排序&#xff08;Selection Sort&#xff09; 核心思想&#xff1a;每次从未排序部分选择最小元素&#xff0c;与未排…...