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,首先 webScoket是HTML5提出的一个基于TCP的一个全双工可靠通讯协议,处在应用层。很多人喜欢说webScoket是一次连接,这是误区,其实他是基于TCP的只不过将三次握手与四次挥手进行隐藏,封装。…...
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账号,最好取一个有意义的名字,比如姓名全拼,昵称全拼,如果被占用,可以加上有意义的数字. 本文中假设用户名为 UNIT-wuji(也是我的博客名) 地址: https:/…...
【Linux详解】——共享内存
📖 前言:本期介绍共享内存。 目录 🕒 1. 共享内存的原理🕒 2. 共享内存的概念🕘 2.1 接口认识🕘 2.2 演示生成key的唯一性🕘 2.3 再谈key 🕒 3. 共享内存相关命令🕒 4. 利…...
Golang 几个不错的实用函数库
文章目录 samber/lothoas/go-funkduke-git/lancetelliotchance/piegookit/goutildablelv/cyan 大咖好呀,我是恋喵大鲤鱼。 Golang 标准库是 Go 语言自带的一组核心功能库,功能全面,易于使用。 在 Golang 标准库的基础上,还可以进…...
【Linux】地址空间概念
目录 前言: 地址空间回顾 验证:一个变量是否会有两个值? 一. 什么是地址空间 虚拟地址与物理地址之间的关系 二. 地址空间是如何设计的 1. 回答一个变量两个值 2.扩展 继续深入理解 三. 为什么要有地址空间 原因: 1. 使…...
视频集中存储/直播点播平台EasyDSS点播文件分类功能新升级
视频推拉流EasyDSS视频直播点播平台,集视频直播、点播、转码、管理、录像、检索、时移回看等功能于一体,可提供音视频采集、视频推拉流、播放H.265编码视频、存储、分发等视频能力服务。 TSINGSEE青犀视频的EasyDSS平台具有点播文件分类展示方法…...
JavaScript基础06——let和var两个关键字有啥不同
哈喽,小伙伴们大家好,我是雷工! 每日学习一点点,今天继续学习JavaScript基础知识,下面是学习笔记。 1、变量的本质 内存:计算机中存储数据的地方,相当于一空间。 变量的本质:是程序…...
Apache Doris 2.0.1 1.2.7 版本正式发布!
亲爱的社区小伙伴们,我们很高兴的宣布,2023 年 9 月 4 日 我们正式发布了 Apache Doris 2.0.1 和 Apache Doris 1.2.7 这两个版本,这两个版本由上百名位贡献者共同努力完成的,提供了更多有用的新特性,同时修复了若干已…...
YOLOv5算法改进(11)— 替换主干网络之EfficientNetv2
前言:Hello大家好,我是小哥谈。EfficientNetV2是一个网络模型,旨在提供更小的模型和更快的训练速度。它是EfficientNetV1的改进版本。EfficientNetV2通过使用更小的模型参数和采用一种称为Progressive Learning的渐进学习策略来实现这一目标。…...
Lombok讲解
Lombok是一个可以通过简单的注解形式来帮助我们简化消除一些必须有但显得很臃肿的Java代码的工具,如:getter、setter、equals、hashCode、toString等。 Lombok的常用注解有: Data:这是一个自定义注解,它相当于Getter…...
【Android】功能丰富的dumpsys activity
在Android中,要查看客户端Binder的连接数,可以通过dumpsys命令结合service参数来获取相关信息。请按照以下步骤进行操作: 连接到设备的计算机上,打开命令行终端。 使用adb shell命令进入设备的Shell环境。 执行以下命令来查看服…...
亚马逊云科技 云技能孵化营——我的云技能之旅
文章目录 每日一句正能量前言活动流程后记 每日一句正能量 不能在已经获得足够多的成功时,还对自己的能力保持怀疑,露出自信的微笑,走出自信的步伐,做一个自信的人! 前言 亚马逊云科技 (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 一、环境信…...
汽车信息安全导图
尊敬的读者们,欢迎来到我的信息安全专栏。在这个专栏中,我将结合我在信息安全领域的开发经验,为大家深入浅出地讲解信息安全的重要性和相关知识点。 在数字化时代,信息成为了我们生活中不可或缺的一部分。我们的个人信息、交易数据、社交网络、公司机密等都以电子形式存储…...
【元宇宙】区块链,元宇宙最大化的驱动力
如今,一些观察者认为区块链是在结构上实现元宇宙的必要条件,而其他人则认为这种说法是荒谬的。人们对于区块链技术本身仍然有很多困惑,所以根本谈不上清楚地了解込块链技术与元宇宙的关系。所以,我们可以从区块链的定义开始介绍。…...
$ref属性的介绍与使用
在Vue.js中,$ref是一个特殊的属性,用于访问Vue组件中的DOM元素或子组件实例。它允许你直接访问组件内部的DOM元素或子组件,并且可以在需要时进行操作或修改。以下是有关$ref的详细介绍和示例演示,给大家做一个简单的介绍和概念区分…...
Holistic Evaluation of Language Models
本文是LLM系列文章,针对《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 这是一种默认的属性,在不进行明确指定的情况下,系…...
北京已收录2023开学了《乡村振兴战略下传统村落文化旅游设计》中国建筑出版传媒许少辉八一新书
北京已收录2023开学了《乡村振兴战略下传统村落文化旅游设计》中国建筑出版传媒许少辉八一新书...
以下是对华为 HarmonyOS NETX 5属性动画(ArkTS)文档的结构化整理,通过层级标题、表格和代码块提升可读性:
一、属性动画概述NETX 作用:实现组件通用属性的渐变过渡效果,提升用户体验。支持属性:width、height、backgroundColor、opacity、scale、rotate、translate等。注意事项: 布局类属性(如宽高)变化时&#…...
8k长序列建模,蛋白质语言模型Prot42仅利用目标蛋白序列即可生成高亲和力结合剂
蛋白质结合剂(如抗体、抑制肽)在疾病诊断、成像分析及靶向药物递送等关键场景中发挥着不可替代的作用。传统上,高特异性蛋白质结合剂的开发高度依赖噬菌体展示、定向进化等实验技术,但这类方法普遍面临资源消耗巨大、研发周期冗长…...
YSYX学习记录(八)
C语言,练习0: 先创建一个文件夹,我用的是物理机: 安装build-essential 练习1: 我注释掉了 #include <stdio.h> 出现下面错误 在你的文本编辑器中打开ex1文件,随机修改或删除一部分,之后…...
镜像里切换为普通用户
如果你登录远程虚拟机默认就是 root 用户,但你不希望用 root 权限运行 ns-3(这是对的,ns3 工具会拒绝 root),你可以按以下方法创建一个 非 root 用户账号 并切换到它运行 ns-3。 一次性解决方案:创建非 roo…...
根据万维钢·精英日课6的内容,使用AI(2025)可以参考以下方法:
根据万维钢精英日课6的内容,使用AI(2025)可以参考以下方法: 四个洞见 模型已经比人聪明:以ChatGPT o3为代表的AI非常强大,能运用高级理论解释道理、引用最新学术论文,生成对顶尖科学家都有用的…...
docker 部署发现spring.profiles.active 问题
报错: org.springframework.boot.context.config.InvalidConfigDataPropertyException: Property spring.profiles.active imported from location class path resource [application-test.yml] is invalid in a profile specific resource [origin: class path re…...
C++:多态机制详解
目录 一. 多态的概念 1.静态多态(编译时多态) 二.动态多态的定义及实现 1.多态的构成条件 2.虚函数 3.虚函数的重写/覆盖 4.虚函数重写的一些其他问题 1).协变 2).析构函数的重写 5.override 和 final关键字 1&#…...
MySQL 部分重点知识篇
一、数据库对象 1. 主键 定义 :主键是用于唯一标识表中每一行记录的字段或字段组合。它具有唯一性和非空性特点。 作用 :确保数据的完整性,便于数据的查询和管理。 示例 :在学生信息表中,学号可以作为主键ÿ…...
规则与人性的天平——由高考迟到事件引发的思考
当那位身着校服的考生在考场关闭1分钟后狂奔而至,他涨红的脸上写满绝望。铁门内秒针划过的弧度,成为改变人生的残酷抛物线。家长声嘶力竭的哀求与考务人员机械的"这是规定",构成当代中国教育最尖锐的隐喻。 一、刚性规则的必要性 …...
CppCon 2015 学习:Reactive Stream Processing in Industrial IoT using DDS and Rx
“Reactive Stream Processing in Industrial IoT using DDS and Rx” 是指在工业物联网(IIoT)场景中,结合 DDS(Data Distribution Service) 和 Rx(Reactive Extensions) 技术,实现 …...
