位置: IT常识 - 正文

WebSocket的心跳机制和断线重连(netty websocket心跳)

编辑:rootadmin
WebSocket的心跳机制和断线重连 背景

推荐整理分享WebSocket的心跳机制和断线重连(netty websocket心跳),希望有所帮助,仅作参考,欢迎阅读内容。

文章相关热门搜索词:netty websocket心跳,socketio心跳,spring boot websocket 心跳机制,socket 心跳,swoole websocket心跳,websocket服务端心跳检测,websocket服务端心跳检测,websocket的心跳机制,内容如对您有帮助,希望把文章链接给更多的朋友!

在服务器重启或是弱网情况下,前端不能保证一直连接成功。因此在出现被动断开的情况下,需要有心跳机制和断线重连的功能。

心跳机制:客户端每隔一段时间向服务端发送一个特有的心跳消息,每次服务端收到消息后只需将消息返回,此时,若二者还保持连接,则客户端就会收到消息,若没收到,则说明连接断开,此时,客户端就要主动重连,完成一个周期

断线重连:若某时间段内客户端发送了消息,而服务端未返回,则认定为断线;这个时候会触发到websocket中的onclose事件,需要重新连接服务

nodejs+ws模块搭建websocket服务器

之前我有篇文章使用的是nodejs+websocket模块搭建的服务器,后来发现ws模块更易使用和社区一直有人维护,因此推荐使用ws模块

下载ws依赖 ws - npm

npm i wsWebSocket的心跳机制和断线重连(netty websocket心跳)

在文件夹下新增server.js文件

/* server.js 服务器 */// 引入模块const WebSocket = require('ws').Serverconst port = 8002// 创建服务器const server = new WebSocket({ port }, () => { console.log('websocket服务开启')})const connectHandler = (ws) => { console.log('客户端连接') // 监听客户端出错 ws.on('error', errorHandler) // 监听客户端断开链接 ws.on('close', closeHandler) // 监听客户端发来的消息 ws.on('message', messageHandler)}// 监听接收客户端信息回调// 注意:因为这里用到this的指向,因此用普通的函数function messageHandler(data) { console.log('messageHandler===>接收客户端消息', JSON.parse(data)) const { ModeCode } = JSON.parse(data) switch(ModeCode) { case 'message': console.log('收到消息') // 需要发送信息给客户端以此说明连接成功 this.send(JSON.stringify(JSON.parse(data))) break; case 'heart_beat': console.log('心跳检测') // 需要发送信息给客户端以此说明连接成功 this.send(JSON.stringify(JSON.parse(data))) break; }}// 监听客户端出错回调const errorHandler = (error) => { console.log('errorHandler===>客户端出错', error)}// 监听客户端断开连接回调const closeHandler = (e) => { console.log('closeHandler===>客户端断开🔗', e)}// 建立连接server.on('connection', connectHandler)客户端的实现

1. 封装websocket,需要实现心跳机制和断线重连

2. 封装自定义通信事件,实现监听和触发功能

在文件夹下新增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()

在文件夹下新增myWebSocket.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 就是指向websocket return 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) break case ModeCodeEnum.HEART_BEAT: // 心跳 this.webSocketState = true console.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 = false setTimeout(() => { // 连线成功状态下 继续心跳检测 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 = true sendMessageBtn.disabled =false closeBtn.disabled = false break case 'close': connectBtn.disabled = false sendMessageBtn.disabled = true closeBtn.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 = () => { // 判断是否有初始化websocket if(!myWS) { connectWeboSocket() return } // 判断实例上的reconnectTimer 是否有值,要记得清除后再连接 if(myWS && myWS.reconnectTimer) { clearTimeout(myWS.reconnectTimer) myWS.reconnectTimer = null connectWeboSocket() } } // 注册设置按钮样式 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>实现心跳机制和断线重连总结

心跳机制的实现,在客户端连接成功的回调中即开启心跳。心跳处理函数内部使用定时器延时触发向服务端发送消息的方法,待服务器将消息返回证明是连线成功状态下,继续调用心跳检测方法。

如果客户端给服务端发送心跳消息,在定义的超时时间后客户端没有收到回复,则说明和服务端断线了,此时会触发到客户端连接关闭的回调函数,在此回调中发起重新连接websocket,如果连接失败继续会触发客户端连接关闭的回调函数继续发起重新连接(如此循环)。

等断线重新连接起来时,在客户端连接成功的回调中又开始了心跳检测。其实就是通过延时的定时器反复以上的操作来和服务端一直通信保持连接。

本文链接地址:https://www.jiuchutong.com/zhishi/290896.html 转载请保留说明!

上一篇:YOLOv5 以txt 或json格式输出预测结果(yolo xml转txt)

下一篇:韦尼格罗德的圣诞市场,德国萨克森-安哈尔特州 (© Krzysztof Baranowski/Moment/Getty Images)(韦罗尼卡)

  • 华为nova7 pro有防水功能吗(华为nova7pro有防蓝光吗)

    华为nova7 pro有防水功能吗(华为nova7pro有防蓝光吗)

  • iphone8p支持红外线吗(iphone8支持红外线)

    iphone8p支持红外线吗(iphone8支持红外线)

  • 苹果打电话怎么录通话录音(苹果打电话怎么换主号副号)

    苹果打电话怎么录通话录音(苹果打电话怎么换主号副号)

  • 华为手机怎么消除杂音(华为手机怎么消除小艺)

    华为手机怎么消除杂音(华为手机怎么消除小艺)

  • qq群视频怎么关闭自己的麦克风(qq群视频怎么关掉下面的头像)

    qq群视频怎么关闭自己的麦克风(qq群视频怎么关掉下面的头像)

  • 华为手机能充一夜电吗(华为手机能充一晚电吗)

    华为手机能充一夜电吗(华为手机能充一晚电吗)

  • 华为手机打字下一行按键在哪(华为手机打字下一行)

    华为手机打字下一行按键在哪(华为手机打字下一行)

  • 菜鸟裹裹一键取件是什么意思(菜鸟裹裹一键取件不见了)

    菜鸟裹裹一键取件是什么意思(菜鸟裹裹一键取件不见了)

  • 苹果下载不了超星(为什么苹果不能下载超级入口)

    苹果下载不了超星(为什么苹果不能下载超级入口)

  • 华为手机怎么知道手机型号(华为手机怎么知道是不是翻新机)

    华为手机怎么知道手机型号(华为手机怎么知道是不是翻新机)

  • 钉钉匿名投票发起人可以看到吗(钉钉匿名投票发起人)

    钉钉匿名投票发起人可以看到吗(钉钉匿名投票发起人)

  • 多媒体技术发展基础是什么(多媒体技术发展的基础是)

    多媒体技术发展基础是什么(多媒体技术发展的基础是)

  • 抖音直播必须是认证本人吗(抖音直播必须是本人吗)

    抖音直播必须是认证本人吗(抖音直播必须是本人吗)

  • 电脑曲面显示器优缺点(电脑曲面显示器哪个牌子比较好)

    电脑曲面显示器优缺点(电脑曲面显示器哪个牌子比较好)

  • 为什么qq老是无响应(为什么qq老是无响应怎么回事vivo)

    为什么qq老是无响应(为什么qq老是无响应怎么回事vivo)

  • 手机网络无法连接怎么办(手机网络无法连接是什么原因)

    手机网络无法连接怎么办(手机网络无法连接是什么原因)

  • iqoo和iqoopro的外观差别(iqoo pro iqoo)

    iqoo和iqoopro的外观差别(iqoo pro iqoo)

  • 息屏显示费电吗(vivo手机熄灭屏幕显示时间)

    息屏显示费电吗(vivo手机熄灭屏幕显示时间)

  • iphonexr应用与数据选哪个(苹果xr手机应用与数据在哪里设置)

    iphonexr应用与数据选哪个(苹果xr手机应用与数据在哪里设置)

  • 华为8x有红外线功能吗(华为手机8x有没有红外线)

    华为8x有红外线功能吗(华为手机8x有没有红外线)

  • 微信语音聊天怎么自动录音(微信语音聊天怎么变声音)

    微信语音聊天怎么自动录音(微信语音聊天怎么变声音)

  • 讯飞输入法朋友圈模式在哪(讯飞输入法朋友圈模式)

    讯飞输入法朋友圈模式在哪(讯飞输入法朋友圈模式)

  • Win10/Win7如何彻底关闭系统进程 Win10/Win7关闭系统进程图文步骤(win7怎么删除windows.old)

    Win10/Win7如何彻底关闭系统进程 Win10/Win7关闭系统进程图文步骤(win7怎么删除windows.old)

  • 【node进阶】在node.js中优雅的使用Socket.IO模块(node-)

    【node进阶】在node.js中优雅的使用Socket.IO模块(node-)

  • 工商年报主营业务怎么填
  • 地税补缴社保
  • 产权转移书据印花税分录
  • 小规模自开专票怎么交税
  • 个人投资者取得现金红利的过程不用支付利息税
  • 收取职工个人部分养老金怎么做分录
  • 购买的固定资产没有使用,是否计提折旧
  • 公司成立前购买的设备算个人还是公司
  • 无形资产减值准备
  • 公司拖欠工资还要继续工作吗?
  • 3%小规模纳税人开出的发票 农产品成本如何计算
  • 豪华小汽车消费税
  • 契税和印花税入哪个科目
  • 发票代码不是10位,怎么提示输入12位的
  • 企业核算方法
  • 用企业资本金购物违法吗
  • 普通发票要写增值税吗
  • 金税盘发票报送状态未报送
  • 跨月可以开票吗
  • 没有购销合同怎么申报印花税
  • win11怎么把默认c盘改到d盘
  • 公司注销要交分红税吗
  • 残疾人保障金是强制性的吗
  • 开红字发票后再开蓝字发票应如何入账?
  • 计提的社保费如何做账
  • windows11永久解决蓝屏
  • php中删除文件的函数
  • 安置房项目需要环评吗
  • 政府会计制度固定资产折旧哪个月开始计提
  • 应付职工薪酬的明细科目有哪些
  • 买货没发票如何入账
  • 工资薪金所得申报流程
  • 向日葵茎上有刺吗
  • 金银首饰消费税计税依据
  • 专项应付款转资本公积需要什么附件
  • php ioc
  • php实现验证码
  • 收到合同预付款怎么处理
  • 企业给企业借款收入会计处理
  • 在access中,数据库对象导出到另一数据库中
  • sqlserver存储过程声明变量
  • 海关缴款书能重开吗
  • 所得税多交退回分录
  • 增值税加计抵减怎么算
  • 个人开咨询费 有哪些税
  • 股东收到投资收益会计科目
  • 公司注册登记需要多少钱
  • 小规模纳税人转一般纳税人当月如何申报
  • 出口后收不到货款
  • 低值易耗品怎么摊
  • 取得下列资产时应按公允价值计量
  • 预提工资如何算增值税
  • 第二个季度
  • 处置固定资产的增值税怎么处理
  • sql server查询
  • 在基于Xen的CentOS系统VPS上配置PPTP VPN的教程
  • freebsd与linux
  • windows.exe
  • window7截图工具无法使用
  • 双系统重装win11
  • ubuntu linux指南:基础篇
  • linux gpfs
  • winxp开启远程控制
  • centos 开机启动
  • 返回场景和音乐的区别
  • win8.1 下 eclipse+android 开发环境配置带图详细教程
  • 调度器在操作系统中的作用
  • 根据安全生产法的规定,生产经营单位
  • jquery 表格 排序
  • python3gui
  • jquery validator
  • python cx_Oracle模块的安装和使用详细介绍
  • js页面点击怎么随机生成图片
  • jquery的实现原理
  • Android ExpandableListView的使用技巧
  • code encode的区别
  • 国家税务总局千户集团
  • 无锡第三税务分局
  • 公司注销时注册资金未缴完
  • 徐州市税务局第三稽查局
  • 免责声明:网站部分图片文字素材来源于网络,如有侵权,请及时告知,我们会第一时间删除,谢谢! 邮箱:opceo@qq.com

    鄂ICP备2023003026号

    网站地图: 企业信息 工商信息 财税知识 网络常识 编程技术

    友情链接: 武汉网站建设