位置: 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)(韦罗尼卡)

  • 京东白条自动还款设置(京东白条自动还款,是扣除银行卡里的钱吗)

    京东白条自动还款设置(京东白条自动还款,是扣除银行卡里的钱吗)

  • 苹果手机流量超了怎么自动关闭通知(苹果手机流量超过200m不能下载)

    苹果手机流量超了怎么自动关闭通知(苹果手机流量超过200m不能下载)

  • 抖音dou+推广审核不通过(抖音dou推广审核时间)

    抖音dou+推广审核不通过(抖音dou推广审核时间)

  • 华为3摄和4摄区别(华为三摄好还是四摄好)

    华为3摄和4摄区别(华为三摄好还是四摄好)

  • 爱彼迎脸部识别为什么没反应(爱彼迎实名认证在哪)

    爱彼迎脸部识别为什么没反应(爱彼迎实名认证在哪)

  • ipad个人热点怎么开(iPad个人热点怎么连接)

    ipad个人热点怎么开(iPad个人热点怎么连接)

  • 快手如何横屏观看视频(快手如何横屏观看)

    快手如何横屏观看视频(快手如何横屏观看)

  • 小米CC9取消指纹解锁在哪里(小米cc9指纹设置选项消失)

    小米CC9取消指纹解锁在哪里(小米cc9指纹设置选项消失)

  • 好评怎么删除或撤回(好评怎么才能删除)

    好评怎么删除或撤回(好评怎么才能删除)

  • 抖音帮别人上热门对方会接到通知吗(抖音帮别人上热门怎么能让别人不知道)

    抖音帮别人上热门对方会接到通知吗(抖音帮别人上热门怎么能让别人不知道)

  • 联想拯救者进入bios设置按哪个键(联想拯救者进入bios按什么键)

    联想拯救者进入bios设置按哪个键(联想拯救者进入bios按什么键)

  • 电脑的声音有滋滋杂音怎么回事(电脑声音滋啦)

    电脑的声音有滋滋杂音怎么回事(电脑声音滋啦)

  • 被群主禁言怎么自己解除(被群主禁言怎么解开)

    被群主禁言怎么自己解除(被群主禁言怎么解开)

  • 华为手机前置摄像头有红光(华为手机前置摄像头像素高的是哪款)

    华为手机前置摄像头有红光(华为手机前置摄像头像素高的是哪款)

  • 小米8多大(小米8多大内存手机)

    小米8多大(小米8多大内存手机)

  • qq好友辅助成功后多久收到信息(qq好友辅助成功没反应)

    qq好友辅助成功后多久收到信息(qq好友辅助成功没反应)

  • 哔哩哔哩22卡和33卡有什么区别(哔哩哔哩22卡和联通王卡哪个好)

    哔哩哔哩22卡和33卡有什么区别(哔哩哔哩22卡和联通王卡哪个好)

  • id被锁了怎么才能解锁(id被锁了怎么才能解锁电子邮件验证不了)

    id被锁了怎么才能解锁(id被锁了怎么才能解锁电子邮件验证不了)

  • 支付宝隐私开关在哪里(支付宝隐私开关打开的的为什么别人还是无法转账)

    支付宝隐私开关在哪里(支付宝隐私开关打开的的为什么别人还是无法转账)

  • 拼多多买家怎么删除评价(拼多多买家怎么查看自己的信誉度)

    拼多多买家怎么删除评价(拼多多买家怎么查看自己的信誉度)

  • 荣耀9x如何设置返回键(荣耀9x如何设置门禁卡)

    荣耀9x如何设置返回键(荣耀9x如何设置门禁卡)

  • 网页怎么取消点赞(取消网页快捷键)

    网页怎么取消点赞(取消网页快捷键)

  • p30pro电池容量(p30pro电池容量在哪里)

    p30pro电池容量(p30pro电池容量在哪里)

  • 劳务费增值税税率13%
  • 资源税类包括哪些税种
  • 民办非企业免税额度
  • 预收款方式销售货物
  • 其他收益科目在哪个科目前面填
  • 小规模免哪些税
  • 发票的抵扣期限怎么填
  • 小规模纳税人的企业所得税税率
  • 没有抵扣的发票怎么入账
  • 贷款应计利息会计分录
  • 单位社保没推送
  • 冲减成本怎么做会计分录
  • 劳服企业可以安差额税上税吗?
  • 增值税预交款怎么算
  • 足疗发票税点
  • 酒店优惠券财务如何记账?
  • 软件企业研发费用占比要求
  • 开户许可证复印件是什么
  • 销售商品结转成本会计分录
  • 个税经营所得申报怎么更正
  • 动产抵押交付生效还是登记生效
  • 进项发票大过销项,退税只退13个点的增值税吗
  • 微软 Windows10
  • js时间格式转换时间戳
  • 基金的管理费用包括什么
  • 创建自定义对象主要哪几种方法,并写出基本语法结构?
  • 补缴税款怎么补
  • 成本核算流程会议记录
  • 企业发生的现金折扣应计入什么费用
  • vue3.0用法
  • 员工报销垫付的钱怎么入账
  • 个人所得税申报流程图
  • 小程序生命周期钩子
  • vue设置元素不可点击
  • 支付给境外个人的服务费
  • html5+css3web前端设计基础教程
  • 关于实收资本的表述中,不正确的是
  • 2022年最新苹果平板电脑
  • PHP MongoDB GridFS 存储文件的方法详解
  • 发票跨月还可以作废吗
  • 应付职工薪酬账户的明细账户有
  • sqlserver2008不存在或拒绝访问怎么办
  • 实收资本结转本年利润
  • 未分配利润可以弥补亏损吗
  • 处置资产增值税纳税义务发生时间
  • 商品互换定义
  • 印花税的征税范围口诀
  • 母子公司之间的借款
  • 劳务派遣公司收入确认税收政策
  • 分期收款定义
  • 投资和注册资本
  • 结转损益利息收入贷方红字什么意思
  • 商业折扣,现金折扣,销售折让
  • 工程施工中购入固定资产
  • 实际利率法仅仅适用于具有本金和利息
  • SQL Server提示"选定的用户拥有对象,所以无法除去该用户”
  • 安装Win8 64位旗舰版系统提示“windows无法安装到这个磁盘”的故障分析及解决方法
  • 巧妙设置Vista任务栏和开始菜单的属性
  • safari macos
  • 虚拟机中的centos怎么联网
  • win8中文版是什么版本
  • ubuntu20 配置静态ip
  • cpu numa
  • centos7网络配置文件在哪
  • 关闭windbg
  • linux tee命令详解
  • win8.1无线
  • windows下合并分区
  • root忘记密码了怎么办
  • nodejs用法
  • xcopy /i
  • Node.js中的全局对象有
  • Node.js+jade+mongodb+mongoose实现爬虫分离入库与生成静态文件的方法
  • android studio右边的视图不见了
  • javascript快速入门
  • [置顶]马粥街残酷史
  • 用原生js实现过什么功能
  • Android应用程序可以直接在ios中安装运行吗
  • 修改季度申报表
  • 增值税发票选择确认平台已勾选未确认的发票怎么撤销?
  • 免责声明:网站部分图片文字素材来源于网络,如有侵权,请及时告知,我们会第一时间删除,谢谢! 邮箱:opceo@qq.com

    鄂ICP备2023003026号

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

    友情链接: 武汉网站建设