稀土掘金技术社区 2024年11月22日
webSocket封装,心跳检测+断线重连基于ES6 class,已在生产环境上使用,已发布包
index_new5.html
../../../zaker_core/zaker_tpl_static/wap/tpl_guoji1.html

 

本文详细介绍了HTML5 WebSocket协议,包括其工作原理、优势、适用场景以及WebSocket API的使用方法。此外,文章还深入探讨了WebSocket的心跳机制,并提供了基于ES6的WebSocket API封装代码,包括心跳检测、断线重连等功能。最后,文章还给出了一个基于Node.js的WebSocket服务器示例,帮助读者更好地理解和应用WebSocket技术。

🚀 **WebSocket协议概述**: WebSocket是一种在单个TCP连接上进行全双工通信的协议,它允许服务器主动向客户端推送数据,并有效降低了带宽消耗,提升了通信效率,相较于传统的Ajax轮询方式具有显著优势。

💡 **WebSocket API介绍**: WebSocket API提供了建立连接、发送数据、接收数据、关闭连接等功能,通过readyState属性可以获取连接状态,通过send()方法发送数据,通过onmessage事件接收服务器返回的数据。

🔄 **心跳机制**: WebSocket心跳机制用于检测连接状态,防止网络断开导致连接失效。封装的心跳基类通过定时发送数据包来确保连接的稳定性,并提供断线重连功能。

📦 **WebSocket API封装**: 文章提供了基于ES6的WebSocket API封装代码,方便开发者快速构建WebSocket应用,该封装支持自定义配置,例如心跳时间间隔、重连次数等。

🖥️ **示例代码及测试**: 文章提供了基于Node.js的WebSocket服务器示例,并展示了测试截图,帮助读者理解WebSocket的使用方法。

原创 禅思院 2024-11-22 08:30 重庆

点击关注公众号,“技术干货” 及时达!

介绍

在《菜鸟教程中》这样介绍WebSocket

特点

适用场景

对数据的实时性要求比较强,客户端与服务频繁交互的场景, 比如:

WebSocket API 介绍

WebSocket 封装思想

    基于上述的API上扩展方法,上述的API 方法通过初始化,和参数一起传入,不用做任何操作,还有直接初始化,之后通过对象调用

    扩展心跳检测

    断线重连

基础知识

    ES6的基础语法

    ES6的class

E6封装部分源码

封装心跳基类

什么是心跳?其实心跳就像人类的心脏一样,有跳动,说明还活着。为什么要使用心跳呢?因为我们在使用WebSocket 的过程中,总会遇到网络断开的情况等各种情况,但是在遇到这些情况的时候服务器端并没有触发 onclose 的事件。这样会有:服务器会继续向客户端发送多余的链接,并且这些数据还会丢失。所以就需要一种机制来检测客户端和服务端是否处于正常的链接状态。因此就有了 WebSocket 的心跳了。还有心跳,说明还活着,没有心跳说明已经挂掉了,是不是相当于人类的心脏。

心跳机制: 本次封装的封装心跳基类,每隔一段时间会向服务器发送一个数据包,告诉服务器自己还活着,同时客户端会确认服务器端是否还活着,如果还活着的话,就会回传一个数据包给客户端来确定服务器端也还活着,否则的话,有可能是网络断开连接了。需要重连。这个间隔时间参数开放,心跳完成有回调函数,该基类适合大多数有这样原理的场景。做到啦全局复用。

心跳基类源码:

/** * 心跳基类 */class Heart {  HEART_TIMEOUT = null // 心跳计时器  SERVER_HEART_TIMEOUT = null // 心跳计时器
constructor () { this.timeout = 5000 } // 重置 reset () { clearTimeout(this.HEART_TIMEOUT) clearTimeout(this.SERVER_HEART_TIMEOUT) return this } /** * 启动心跳 * @param {Function} cb 回调函数 */ start (cb) { this.HEART_TIMEOUT = setTimeout(() => { cb() this.SERVER_HEART_TIMEOUT = setTimeout(() => { cb() // 重新开始检测 this.reset().start(cb) // this.reset().start(cb()) }, this.timeout) }, this.timeout) }}

封装WebSocket API

该封装可以在首次吃实话传入各种配置,永久使用,也可以通过实例化进行调用。

封装WebSocket类源码:

** *  OPTIONS = { *    url: null, // 链接的通道的地址 *    heartTime: 5000, // 心跳时间间隔 *    heartMsg: 'ping', // 心跳信息,默认为'ping' *    isReconnect: true, // 是否自动重连 *    isRestory: false, // 是否销毁 *    reconnectTime: 5000, // 重连时间间隔 *    reconnectCount: 5, // 重连次数 -1 则不限制 *    openCb: null, // 连接成功的回调 *    closeCb: null, // 关闭的回调 *    messageCb: null, // 消息的回调 *    errorCb: null // 错误的回调 *   } */class Socket extends Heart {  ws = null
RECONNEC_TTIMER = null // 重连计时器 RECONNECT_COUNT = 10 // 变量保存,防止丢失
OPTIONS = { url: null, // 链接的通道的地址 heartTime: 5000, // 心跳时间间隔 heartMsg: 'ping', // 心跳信息,默认为'ping' isReconnect: true, // 是否自动重连 isRestory: false, // 是否销毁 reconnectTime: 5000, // 重连时间间隔 reconnectCount: 5, // 重连次数 -1 则不限制 openCb: null, // 连接成功的回调 closeCb: null, // 关闭的回调 messageCb: null, // 消息的回调 errorCb: null // 错误的回调 } constructor (ops) { super() Object.assign(this.OPTIONS, ops) this.create() } /** * 建立连接 */ create () { if (!('WebSocket' in window)) { /* eslint-disable no-new */ new Error('当前浏览器不支持,无法使用') return } if (!this.OPTIONS.url) { new Error('地址不存在,无法建立通道') return } delete this.ws this.ws = new WebSocket(this.OPTIONS.url) this.onopen() this.onclose() this.onmessage() } /** * 自定义连接成功事件 * 如果callback存在,调用callback,不存在调用OPTIONS中的回调 * @param {Function} callback 回调函数 */ onopen (callback) { this.ws.onopen = (event) => { clearTimeout(this.RECONNEC_TTIMER) // 清除重连定时器 this.OPTIONS.reconnectCount = this.RECONNECT_COUNT // 计数器重置 // 建立心跳机制 super.reset().start(() => { this.send(this.OPTIONS.heartMsg) }) if (typeof callback === 'function') { callback(event) } else { (typeof this.OPTIONS.openCb === 'function') && this.OPTIONS.openCb(event) } } } /** * 自定义关闭事件 * 如果callback存在,调用callback,不存在调用OPTIONS中的回调 * @param {Function} callback 回调函数 */ onclose (callback) { this.ws.onclose = (event) => { super.reset() !this.OPTIONS.isRestory && this.onreconnect() if (typeof callback === 'function') { callback(event) } else { (typeof this.OPTIONS.closeCb === 'function') && this.OPTIONS.closeCb(event) } } } /** * 自定义错误事件 * 如果callback存在,调用callback,不存在调用OPTIONS中的回调 * @param {Function} callback 回调函数 */ onerror (callback) { this.ws.onerror = (event) => { if (typeof callback === 'function') { callback(event) } else { (typeof this.OPTIONS.errorCb === 'function') && this.OPTIONS.errorCb(event) } } }........ /** * 销毁 */ destroy () { super.reset() clearTimeout(this.RECONNEC_TTIMER) // 清除重连定时器 this.OPTIONS.isRestory = true this.ws.close() }}

测试

本次测试是基于nodejs 的 nodejs-websocket 模块来实现的一个简单的demo

部分源码

const createServer = ws.createServer(function (conn) {  //计算心跳时间  conn.heart_time = 0
let timer = setInterval(() => { //检查心跳时间 if (conn.heart_time > heart_beat) { clearInterval(timer); conn.close() } conn.heart_time++ }, 1000) //uid let uid = conn.path.split('/')[conn.path.split('/').length - 1] || '0' conn.uid = uid console.log(`用户${uid}已经连接`) conn.sendText(`Hello 用户${uid}!`)..... //处理错误事件信息 conn.on('error', function (err) { console.log('用户' + uid + ' 已经断开连接,错误原因: ' + err) })}).listen(7041);

测试截图

资源

【Websocket  详解】http://www.ruanyifeng.com/blog/2017/05/websocket.html【Node 模拟 Websocket 知识点链接】https://github.com/theturtle32/WebSocket-Node

仓库地址

Githubnpm

点击关注公众号,“技术干货” 及时达!

阅读原文

跳转微信打开

Fish AI Reader

Fish AI Reader

AI辅助创作,多种专业模板,深度分析,高质量内容生成。从观点提取到深度思考,FishAI为您提供全方位的创作支持。新版本引入自定义参数,让您的创作更加个性化和精准。

FishAI

FishAI

鱼阅,AI 时代的下一个智能信息助手,助你摆脱信息焦虑

联系邮箱 441953276@qq.com

相关标签

WebSocket HTML5 实时通信 心跳机制 API封装
相关文章