WebSocket详解与封装工具类
一、前言
在我们了解websocket之前,不妨先想想这几个问题:
- websocket是什么?
- websocket有什么好处和特点?
- 为什么要用到websocket?
- 什么情况下会用到websocket?
好了,带着这几个疑问一起来了解一下websocket。
二、websocket简介
2.1 什么是websocket
WebSocket是HTML5开始提供的一种基于TCP的协议,用于在客户端和服务器之间建立持久连接,实现实时通讯的功能。
早期,客户端如果想实时拿到浏览器的最新数据就必须要通过发送http请求定时做轮询。每隔一段时间去向浏览器请求最新数据,这样大大的消耗了服务器的资源。
当使用了websocket与服务器建立连接,就不需要反复去轮询请求数据;当有最新消息时服务器会返回给客户端,而websocket可以立马监听到服务器的返回消息。
2.2 websocket的特点
2.2.1 优点
- 可以说实现连接的持久化,使客户端与服务器可以实时双向通讯;
- 减少了HTTP请求,大大减少了服务器的资源消耗,降低了网络负载;
- 没有同源限制,客户端可以与任意服务器通信;
- 协议标识符为ws,如果是加密的话就是wss;
2.2.2 缺点
- 有兼容问题,有一些老版本的浏览器不支持,同时有一些网络代理或防火墙会阻止连接;
- 缺乏安全策略,前面讲过没有同源策略的限制(这个需要注意);
- 对网络要求比较高,如果网络波动频繁可以回导致经常断联(导致断联原因不好排查);
- 需要保持长连接也会占用服务器的较多资源;
- 不适合大文件传输,websocket协议发送数据包不能超过2GB;
2.3 使用场景
websocket的主要优点就是保持客户端与服务端双向实时通讯,所以他主要的引用场景在于:
- 在线聊天室、游戏消息推送;
- 多媒体对话,例如视频会议等;
- 网页更新实时的数据流,股票价格波动、票房分析等;
三、websocket对象详解
WebSocket
对象提供了用于创建和管理 WebSocket]连接,以及可以通过该连接发送和接收数据的 API。
3.1 实例属性
通过使用WebSocket()构造函数来实例化一个WebSocket对象。
3.1.1 url
Websocket的绝对路径(只读)
3.1.2 readyState
WebSocket当前连接的状态(只读)
- WebSocket.CONNECTING:正在连接中
- WebSocket.OPEN:已经连接可以通信
- WebSocket.CLOSING:连接正在关闭
- 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版 上一次编辑位置不见了,研究发现移到了左下角了ÿ…...

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 表现层:页面展示 业务层:逻辑处理 持久层:持久数据化保存 在这里插入图片描述 Mybatis快速入门 
令牌桶 滑动窗口->限流 分布式信号量->限并发的原理 lua脚本分析介绍
文章目录 前言限流限制并发的实际理解限流令牌桶代码实现结果分析令牌桶lua的模拟实现原理总结: 滑动窗口代码实现结果分析lua脚本原理解析 限并发分布式信号量代码实现结果分析lua脚本实现原理 双注解去实现限流 并发结果分析: 实际业务去理解体会统一注…...
聊一聊接口测试的意义有哪些?
目录 一、隔离性 & 早期测试 二、保障系统集成质量 三、验证业务逻辑的核心层 四、提升测试效率与覆盖度 五、系统稳定性的守护者 六、驱动团队协作与契约管理 七、性能与扩展性的前置评估 八、持续交付的核心支撑 接口测试的意义可以从四个维度展开,首…...

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

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

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

c++第七天 继承与派生2
这一篇文章主要内容是 派生类构造函数与析构函数 在派生类中重写基类成员 以及多继承 第一部分:派生类构造函数与析构函数 当创建一个派生类对象时,基类成员是如何初始化的? 1.当派生类对象创建的时候,基类成员的初始化顺序 …...
拟合问题处理
在机器学习中,核心任务通常围绕模型训练和性能提升展开,但你提到的 “优化训练数据解决过拟合” 和 “提升泛化性能解决欠拟合” 需要结合更准确的概念进行梳理。以下是对机器学习核心任务的系统复习和修正: 一、机器学习的核心任务框架 机…...

ZYNQ学习记录FPGA(二)Verilog语言
一、Verilog简介 1.1 HDL(Hardware Description language) 在解释HDL之前,先来了解一下数字系统设计的流程:逻辑设计 -> 电路实现 -> 系统验证。 逻辑设计又称前端,在这个过程中就需要用到HDL,正文…...
用js实现常见排序算法
以下是几种常见排序算法的 JS实现,包括选择排序、冒泡排序、插入排序、快速排序和归并排序,以及每种算法的特点和复杂度分析 1. 选择排序(Selection Sort) 核心思想:每次从未排序部分选择最小元素,与未排…...