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

webScoket长连接人性化解读

今天我们来整理一下webScoket,首先 webScoket是HTML5提出的一个基于TCP的一个全双工可靠通讯协议,处在应用层。很多人喜欢说webScoket是一次连接,这是误区,其实他是基于TCP的只不过将三次握手与四次挥手进行隐藏,封装。

以上是概念性的,个人理解为 webScoket是 TCP连接的升级版本,解决了数据实时推送,服务器不能主动推送数据,客户端发起多次http请求到服务器资源浏览器必须经过长时间轮询等等问题。

有人会问 怎么保证webScoket长连接的可靠性,比如前端不可控制的弱网或者服务器重启的情况下如何保证连接未中断?

其实相对应的会有一个心跳包机制来监听这个连接是否可靠。如果断开那么就会启动断线重连

心跳包机制定时向服务器发送特有的心跳消息,服务器收到消息后只需要返回消息,此时客户端若收到到消息表示这个连接依旧可靠,若是客户端未收到消息表示连接断开,这时候需要启动断线重连,完成一个周期。

短线重连:触发webScoket的onclose事件,重新连接服务器

让我面前端来实现一个webScoket 

新建一个eventBus.js文件

// eventBus.js
// 用到了发布订阅模式
class EventBus {constructor() {// 消息中心,记录了所有的事件 以及 事件对应的处理函数this.subs = Object.create(null)}// 注册时间// 参数:1.事件名称  2.事件处理函数on(eventType, handler) {this.subs[eventType] = this.subs[eventType] || []this.subs[eventType].push(handler)}// 触发事件// 参数: 1.事件名称 2.接收的参数emit(eventType, ...ars) {if(this.subs[eventType]) {this.subs[eventType].forEach(handler => {handler(...ars)})}}
}export default new EventBus()

新增一个myWebscoket.js文件

// myWebSocket.js  单独把websocket的处理方法抽离出来
import eventBus  from "./eventBus.js"
// 定义websocket消息类型
const ModeCodeEnum = {MSG: 'message', // 普通消息HEART_BEAT: 'heart_beat'  // 心跳
}
class MyWebSocket extends WebSocket {constructor (url) {super(url)return this}/*** heartBeatConfig 心跳连接参数*    time: 心跳时间间隔*    timeout: 心跳超时间隔*    reconnect: 断线重连时间间隔* isReconnect 是否断线重连*/init (heartBeatConfig, isReconnect) {this.onopen = this.openHandler // 连接成功后的回调函数this.onclose = this.closeHandler // 连接关闭后的回调 函数this.onmessage = this.messageHandler // 收到服务器数据后的回调函数this.onerror = this.errorHandler // 连接发生错误的回调方法this.heartBeatConfig = heartBeatConfig // 心跳连接配置参数this.isReconnect = isReconnect // 记录是否断线重连this.reconnectTimer = null // 记录断线重连的时间器this.startHeartBeatTimer = null // 记录心跳时间器this.webSocketState = false // 记录socket连接状态 true为已连接}// 获取消息getMessage ({ data }) {return JSON.parse(data)}// 发送消息sendMessage (data) {// 当前的this 就是指向websocketreturn this.send(JSON.stringify(data))}// 连接成功后的回调函数openHandler () {console.log('====onopen 连接成功====')// 触发事件更改按钮的状态eventBus.emit('changeBtnState', 'open')// socket状态设置为连接,做为后面的断线重连的拦截器this.webSocketState = true// 判断是否启动心跳机制if(this.heartBeatConfig && this.heartBeatConfig.time) {this.startHeartBeat(this.heartBeatConfig.time)}}// 收到服务器数据后的回调函数 messageHandler (data) {const { ModeCode, msg} = this.getMessage(data)switch (ModeCode) {case ModeCodeEnum.MSG: // 普通消息类型console.log('====onmessage 有新消息啦====', msg)breakcase ModeCodeEnum.HEART_BEAT: // 心跳this.webSocketState = trueconsole.log('====onmessage 心跳响应====', msg)break} }// 连接关闭后的回调 函数closeHandler () {console.log('====onclose websocket关闭连接====')// 触发事件更改按钮的状态eventBus.emit('changeBtnState', 'close')// 设置socket状态为断线this.webSocketState = false// 在断开连接时 记得要清楚心跳时间器和 断开重连时间器材this.startHeartBeatTimer && clearTimeout(this.startHeartBeatTimer)this.reconnectTimer && clearTimeout(this.reconnectTimer)this.reconnectWebSocket()}errorHandler () {console.log('====onerror websocket连接出错====')// 触发事件更改按钮的状态eventBus.emit('changeBtnState', 'close')// 设置socket状态为断线this.webSocketState = false// 重新连接this.reconnectWebSocket()}// 心跳初始化方法 time:心跳间隔startHeartBeat (time) {this.startHeartBeatTimer = setTimeout(() => {// 客户端每隔一段时间向服务端发送一个心跳消息this.sendMessage({ModeCode: ModeCodeEnum.HEART_BEAT,msg: Date.now()})this.waitingServer()}, time);}//在客户端发送消息之后,延时等待服务器响应,通过webSocketState判断是否连线成功waitingServer () {this.webSocketState = falsesetTimeout(() => {// 连线成功状态下 继续心跳检测if(this.webSocketState) {this.startHeartBeat(this.heartBeatConfig.time)return}console.log('心跳无响应, 已经和服务端断线')// 重新连接时,记得要先关闭当前连接try {this.close()} catch (error) {console.log('当前连接已经关闭')}// // 重新连接// this.reconnectWebSocket()}, this.heartBeatConfig.timeout)}// 重新连接reconnectWebSocket () {// 判断是否是重新连接状态(即被动状态断线),如果是主动断线的不需要重新连接if(!this.isReconnect) {return}// 根据传入的断线重连时间间隔 延时连接this.reconnectTimer = setTimeout(() => {// 触发重新连接事件eventBus.emit('reconnect')}, this.heartBeatConfig.reconnect)}
}
export default MyWebSocket

在index.html文件,引入eventBus.js和myWebSocket.js 文件

<html lang="en">
<body><div><button id="connect">连接</button><button disabled id="sendMessage">发送</button><button disabled id="close">关闭</button></div>
</body>
</html>
<script type="module">import eventBus from './eventBus.js'import MyWebsocket from './myWebSocket.js'const connectBtn = document.getElementById('connect')const sendMessageBtn = document.getElementById('sendMessage')const closeBtn = document.getElementById('close')const wsUrl = 'ws://127.0.0.1:8002'let myWS = null //  // 用来记录是否连接了websocket// 处理下按钮的状态,连接情况下才能有发送和关闭功能,关闭情况下只能有连接功能const setButtonState = (state) => {switch(state) {case 'open':connectBtn.disabled = truesendMessageBtn.disabled =falsecloseBtn.disabled = falsebreakcase 'close':connectBtn.disabled = falsesendMessageBtn.disabled = truecloseBtn.disabled = true}}// 连接websocket处理函数const connectWeboSocket = () => {myWS = new MyWebsocket(wsUrl)// 调用实例对象的init函数 myWS.init({time: 4 * 1000,timeout: 2 * 1000,reconnect: 3 * 1000}, true)}// 重新连接webscoket处理 函数const reconnectWebSocket = () => {// 判断是否有初始化websocketif(!myWS) {connectWeboSocket()return}// 判断实例上的reconnectTimer 是否有值,要记得清除后再连接if(myWS && myWS.reconnectTimer) {clearTimeout(myWS.reconnectTimer)myWS.reconnectTimer = nullconnectWeboSocket()}}// 注册设置按钮样式eventBus.on('changeBtnState', setButtonState)// 注册重连websocket 事件eventBus.on('reconnect', reconnectWebSocket)// 点击连接按钮 连接websocket服务器connectBtn.addEventListener('click', reconnectWebSocket)// 点击发送按钮 向服务端传送数据sendMessageBtn.addEventListener('click', e => {myWS.sendMessage({ModeCode: "message",msg: 'hello world'})})// 点击关闭按钮 断开连接closeBtn.addEventListener('click', e => {myWS.close()myWS = null})
</script>

这样就实现了一个简易的webScoket长连接demo,这里包括心跳包机制与断线重连,自定义通信事件,实现监听与触发功能。

相关文章:

webScoket长连接人性化解读

今天我们来整理一下webScoket&#xff0c;首先 webScoket是HTML5提出的一个基于TCP的一个全双工可靠通讯协议&#xff0c;处在应用层。很多人喜欢说webScoket是一次连接&#xff0c;这是误区&#xff0c;其实他是基于TCP的只不过将三次握手与四次挥手进行隐藏&#xff0c;封装。…...

ESDA in PySal (1) 利用 A-DBSCAN 聚类点并探索边界模糊性

ESDA in PySAL (1) 利用 A-DBSCAN 聚类点并探索边界模糊性 在本例中,我们将以柏林的 AirBnb 房源样本为例,说明如何使用 A-DBSCAN (Arribas-Bel et al., 2019)。A-DBSCAN 可以让我们做两件事: 识别高密度 AirBnb 房源集群并划定其边界探索这些边界的稳定性%matplotlib inli…...

利用GitHub实现域名跳转

利用GitHub实现域名跳转 一、注册一个 github账号 你需要注册一个 github账号,最好取一个有意义的名字&#xff0c;比如姓名全拼&#xff0c;昵称全拼&#xff0c;如果被占用&#xff0c;可以加上有意义的数字. 本文中假设用户名为 UNIT-wuji(也是我的博客名) 地址: https:/…...

【Linux详解】——共享内存

&#x1f4d6; 前言&#xff1a;本期介绍共享内存。 目录 &#x1f552; 1. 共享内存的原理&#x1f552; 2. 共享内存的概念&#x1f558; 2.1 接口认识&#x1f558; 2.2 演示生成key的唯一性&#x1f558; 2.3 再谈key &#x1f552; 3. 共享内存相关命令&#x1f552; 4. 利…...

Golang 几个不错的实用函数库

文章目录 samber/lothoas/go-funkduke-git/lancetelliotchance/piegookit/goutildablelv/cyan 大咖好呀&#xff0c;我是恋喵大鲤鱼。 Golang 标准库是 Go 语言自带的一组核心功能库&#xff0c;功能全面&#xff0c;易于使用。 在 Golang 标准库的基础上&#xff0c;还可以进…...

【Linux】地址空间概念

目录 前言&#xff1a; 地址空间回顾 验证&#xff1a;一个变量是否会有两个值&#xff1f; 一. 什么是地址空间 虚拟地址与物理地址之间的关系 二. 地址空间是如何设计的 1. 回答一个变量两个值 2.扩展 继续深入理解 三. 为什么要有地址空间 原因&#xff1a; 1. 使…...

视频集中存储/直播点播平台EasyDSS点播文件分类功能新升级

视频推拉流EasyDSS视频直播点播平台&#xff0c;集视频直播、点播、转码、管理、录像、检索、时移回看等功能于一体&#xff0c;可提供音视频采集、视频推拉流、播放H.265编码视频、存储、分发等视频能力服务。 TSINGSEE青犀视频的EasyDSS平台具有点播文件分类展示方法&#xf…...

JavaScript基础06——let和var两个关键字有啥不同

哈喽&#xff0c;小伙伴们大家好&#xff0c;我是雷工&#xff01; 每日学习一点点&#xff0c;今天继续学习JavaScript基础知识&#xff0c;下面是学习笔记。 1、变量的本质 内存&#xff1a;计算机中存储数据的地方&#xff0c;相当于一空间。 变量的本质&#xff1a;是程序…...

Apache Doris 2.0.1 1.2.7 版本正式发布!

亲爱的社区小伙伴们&#xff0c;我们很高兴的宣布&#xff0c;2023 年 9 月 4 日 我们正式发布了 Apache Doris 2.0.1 和 Apache Doris 1.2.7 这两个版本&#xff0c;这两个版本由上百名位贡献者共同努力完成的&#xff0c;提供了更多有用的新特性&#xff0c;同时修复了若干已…...

YOLOv5算法改进(11)— 替换主干网络之EfficientNetv2

前言&#xff1a;Hello大家好&#xff0c;我是小哥谈。EfficientNetV2是一个网络模型&#xff0c;旨在提供更小的模型和更快的训练速度。它是EfficientNetV1的改进版本。EfficientNetV2通过使用更小的模型参数和采用一种称为Progressive Learning的渐进学习策略来实现这一目标。…...

Lombok讲解

Lombok是一个可以通过简单的注解形式来帮助我们简化消除一些必须有但显得很臃肿的Java代码的工具&#xff0c;如&#xff1a;getter、setter、equals、hashCode、toString等。 Lombok的常用注解有&#xff1a; Data&#xff1a;这是一个自定义注解&#xff0c;它相当于Getter…...

【Android】功能丰富的dumpsys activity

在Android中&#xff0c;要查看客户端Binder的连接数&#xff0c;可以通过dumpsys命令结合service参数来获取相关信息。请按照以下步骤进行操作&#xff1a; 连接到设备的计算机上&#xff0c;打开命令行终端。 使用adb shell命令进入设备的Shell环境。 执行以下命令来查看服…...

亚马逊云科技 云技能孵化营——我的云技能之旅

文章目录 每日一句正能量前言活动流程后记 每日一句正能量 不能在已经获得足够多的成功时&#xff0c;还对自己的能力保持怀疑&#xff0c;露出自信的微笑&#xff0c;走出自信的步伐&#xff0c;做一个自信的人&#xff01; 前言 亚马逊云科技 (Amazon Web Services) 是全球云…...

南大通用数据库-Gbase-8a-学习-38-常规日志(general log)

目录 一、环境信息 二、general log的用途 三、general log相关参数介绍 四、LInux环境模拟实验 1、查看参数配置 2、开启general log 3、输入测试SQL 4、查看文件级别general log 5、改为表级别general log 6、再次输入测试SQL 7、查看gbase.general_log 一、环境信…...

汽车信息安全导图

尊敬的读者们,欢迎来到我的信息安全专栏。在这个专栏中,我将结合我在信息安全领域的开发经验,为大家深入浅出地讲解信息安全的重要性和相关知识点。 在数字化时代,信息成为了我们生活中不可或缺的一部分。我们的个人信息、交易数据、社交网络、公司机密等都以电子形式存储…...

【元宇宙】区块链,元宇宙最大化的驱动力

如今&#xff0c;一些观察者认为区块链是在结构上实现元宇宙的必要条件&#xff0c;而其他人则认为这种说法是荒谬的。人们对于区块链技术本身仍然有很多困惑&#xff0c;所以根本谈不上清楚地了解込块链技术与元宇宙的关系。所以&#xff0c;我们可以从区块链的定义开始介绍。…...

$ref属性的介绍与使用

在Vue.js中&#xff0c;$ref是一个特殊的属性&#xff0c;用于访问Vue组件中的DOM元素或子组件实例。它允许你直接访问组件内部的DOM元素或子组件&#xff0c;并且可以在需要时进行操作或修改。以下是有关$ref的详细介绍和示例演示&#xff0c;给大家做一个简单的介绍和概念区分…...

Holistic Evaluation of Language Models

本文是LLM系列文章&#xff0c;针对《Holistic Evaluation of Language Models》的翻译。 语言模型的整体评价 摘要1 引言2 前言3 核心场景4 一般指标5 有针对性的评估6 模型7 通过提示进行调整8 实验和结果9 相关工作和讨论10 缺失11 不足和未来工作12 结论 摘要 语言模型&a…...

android 布局 横屏 android横屏适配

一、刘海屏适配 1、layoutInDisplayCutoutMode属性 Android 9.0系统中提供了3种layoutInDisplayCutoutMode属性来允许应用自主决定该如何对刘海屏设备进行适配。 LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT 这是一种默认的属性&#xff0c;在不进行明确指定的情况下&#xff0c;系…...

北京已收录2023开学了《乡村振兴战略下传统村落文化旅游设计》中国建筑出版传媒许少辉八一新书

北京已收录2023开学了《乡村振兴战略下传统村落文化旅游设计》中国建筑出版传媒许少辉八一新书...

后进先出(LIFO)详解

LIFO 是 Last In, First Out 的缩写&#xff0c;中文译为后进先出。这是一种数据结构的工作原则&#xff0c;类似于一摞盘子或一叠书本&#xff1a; 最后放进去的元素最先出来 -想象往筒状容器里放盘子&#xff1a; &#xff08;1&#xff09;你放进的最后一个盘子&#xff08…...

【Axure高保真原型】引导弹窗

今天和大家中分享引导弹窗的原型模板&#xff0c;载入页面后&#xff0c;会显示引导弹窗&#xff0c;适用于引导用户使用页面&#xff0c;点击完成后&#xff0c;会显示下一个引导弹窗&#xff0c;直至最后一个引导弹窗完成后进入首页。具体效果可以点击下方视频观看或打开下方…...

未来机器人的大脑:如何用神经网络模拟器实现更智能的决策?

编辑&#xff1a;陈萍萍的公主一点人工一点智能 未来机器人的大脑&#xff1a;如何用神经网络模拟器实现更智能的决策&#xff1f;RWM通过双自回归机制有效解决了复合误差、部分可观测性和随机动力学等关键挑战&#xff0c;在不依赖领域特定归纳偏见的条件下实现了卓越的预测准…...

23-Oracle 23 ai 区块链表(Blockchain Table)

小伙伴有没有在金融强合规的领域中遇见&#xff0c;必须要保持数据不可变&#xff0c;管理员都无法修改和留痕的要求。比如医疗的电子病历中&#xff0c;影像检查检验结果不可篡改行的&#xff0c;药品追溯过程中数据只可插入无法删除的特性需求&#xff1b;登录日志、修改日志…...

Linux简单的操作

ls ls 查看当前目录 ll 查看详细内容 ls -a 查看所有的内容 ls --help 查看方法文档 pwd pwd 查看当前路径 cd cd 转路径 cd .. 转上一级路径 cd 名 转换路径 …...

2.Vue编写一个app

1.src中重要的组成 1.1main.ts // 引入createApp用于创建应用 import { createApp } from "vue"; // 引用App根组件 import App from ./App.vue;createApp(App).mount(#app)1.2 App.vue 其中要写三种标签 <template> <!--html--> </template>…...

生成 Git SSH 证书

&#x1f511; 1. ​​生成 SSH 密钥对​​ 在终端&#xff08;Windows 使用 Git Bash&#xff0c;Mac/Linux 使用 Terminal&#xff09;执行命令&#xff1a; ssh-keygen -t rsa -b 4096 -C "your_emailexample.com" ​​参数说明​​&#xff1a; -t rsa&#x…...

Neo4j 集群管理:原理、技术与最佳实践深度解析

Neo4j 的集群技术是其企业级高可用性、可扩展性和容错能力的核心。通过深入分析官方文档,本文将系统阐述其集群管理的核心原理、关键技术、实用技巧和行业最佳实践。 Neo4j 的 Causal Clustering 架构提供了一个强大而灵活的基石,用于构建高可用、可扩展且一致的图数据库服务…...

土地利用/土地覆盖遥感解译与基于CLUE模型未来变化情景预测;从基础到高级,涵盖ArcGIS数据处理、ENVI遥感解译与CLUE模型情景模拟等

&#x1f50d; 土地利用/土地覆盖数据是生态、环境和气象等诸多领域模型的关键输入参数。通过遥感影像解译技术&#xff0c;可以精准获取历史或当前任何一个区域的土地利用/土地覆盖情况。这些数据不仅能够用于评估区域生态环境的变化趋势&#xff0c;还能有效评价重大生态工程…...

Matlab | matlab常用命令总结

常用命令 一、 基础操作与环境二、 矩阵与数组操作(核心)三、 绘图与可视化四、 编程与控制流五、 符号计算 (Symbolic Math Toolbox)六、 文件与数据 I/O七、 常用函数类别重要提示这是一份 MATLAB 常用命令和功能的总结,涵盖了基础操作、矩阵运算、绘图、编程和文件处理等…...