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

封装一个websocket,支持断网重连、心跳检测,拿来开箱即用

封装一个websocket,支持断网重连、心跳检测

代码封装

编写 WebSocketClient.js

import { EventDispatcher } from './dispatcher'export class WebSocketClient extends EventDispatcher {constructor(url) {console.log(url, 'urlurl')super()this.url = url}// #socket实例socket = null// #重连次数reconnectAttempts = 0// #最大重连数maxReconnectAttempts = 5// #重连间隔reconnectInterval = 10000 // 10 seconds// #发送心跳数据间隔heartbeatInterval = 1000 * 30// #计时器idheartbeatTimer = undefined// #彻底终止wsstopWs = false// >生命周期钩子onopen(callBack) {this.addEventListener('open', callBack)}onmessage(callBack) {this.addEventListener('message', callBack)}onclose(callBack) {this.addEventListener('close', callBack)}onerror(callBack) {this.addEventListener('error', callBack)}// >消息发送send(message) {if (this.socket && this.socket.readyState === WebSocket.OPEN) {this.socket.send(message)} else {console.error('[WebSocket] 未连接')}}// !初始化连接connect() {if (this.reconnectAttempts === 0) {this.log('WebSocket', `初始化连接中...          ${this.url}`)}if (this.socket && this.socket.readyState === WebSocket.OPEN) {return}this.socket = new WebSocket(this.url)// !websocket连接成功this.socket.onopen = (event) => {this.stopWs = false// 重置重连尝试成功连接this.reconnectAttempts = 0// 在连接成功时停止当前的心跳检测并重新启动this.startHeartbeat()this.log('WebSocket', `连接成功,等待服务端数据推送[onopen]...     ${this.url}`)this.dispatchEvent('open', event)}this.socket.onmessage = (event) => {this.dispatchEvent('message', event)this.startHeartbeat()}this.socket.onclose = (event) => {if (this.reconnectAttempts === 0) {this.log('WebSocket', `连接断开[onclose]...    ${this.url}`)}if (!this.stopWs) {this.handleReconnect()}this.dispatchEvent('close', event)}this.socket.onerror = (event) => {if (this.reconnectAttempts === 0) {this.log('WebSocket', `连接异常[onerror]...    ${this.url}`)}this.closeHeartbeat()this.dispatchEvent('error', event)}}// > 断网重连逻辑handleReconnect() {if (this.reconnectAttempts < this.maxReconnectAttempts) {this.reconnectAttempts++this.log('WebSocket',`尝试重连... (${this.reconnectAttempts}/${this.maxReconnectAttempts})       ${this.url}`)setTimeout(() => {this.connect()}, this.reconnectInterval)} else {this.closeHeartbeat()this.log('WebSocket', `最大重连失败,终止重连: ${this.url}`)}}// >关闭连接close() {if (this.socket) {this.stopWs = truethis.socket.close()this.socket = nullthis.removeEventListener('open')this.removeEventListener('message')this.removeEventListener('close')this.removeEventListener('error')}this.closeHeartbeat()}// >开始心跳检测 -> 定时发送心跳消息startHeartbeat() {if (this.stopWs) returnif (this.heartbeatTimer) {this.closeHeartbeat()}this.heartbeatTimer = setInterval(() => {if (this.socket) {this.socket.send(JSON.stringify({ type: 'heartBeat', data: {} }))this.log('WebSocket', '送心跳数据...')} else {console.error('[WebSocket] 未连接')}}, this.heartbeatInterval)}// >关闭心跳closeHeartbeat() {clearInterval(this.heartbeatTimer)this.heartbeatTimer = undefined}
}

引用的 dispatcher.js 源码

import { Log } from './log'export class EventDispatcher extends Log {constructor() {super()this.listeners = {}}addEventListener(type, listener) {if (!this.listeners[type]) {this.listeners[type] = []}if (this.listeners[type].indexOf(listener) === -1) {this.listeners[type].push(listener)}}removeEventListener(type) {this.listeners[type] = []}dispatchEvent(type, data) {const listenerArray = this.listeners[type] || []if (listenerArray.length === 0) returnlistenerArray.forEach((listener) => {listener.call(this, data)})}
}

上面还用到了一个 log.js ,用于美化控制台打印的,这个文件在其他地方也通用

export class Log {static console = truelog(title, text) {if (!Log.console) returnconst color = '#09c'console.log(`%c ${title} %c ${text} %c`,`background:${color};border:1px solid ${color}; padding: 1px; border-radius: 2px 0 0 2px; color: #fff;`,`border:1px solid ${color}; padding: 1px; border-radius: 0 2px 2px 0; color: ${color};`,'background:transparent')}closeConsole() {Log.console = false}
}

至此一个 WebSocket 就封装好了

使用方法

首先使用node编写一个后端服务,用于 WebSocket 连接

需要安装一下 ws

npm install ws
const WebSocket = require("ws");const wss = new WebSocket.Server({port: 3200});console.log("服务运行在http://localhost:3200/");wss.on("connection", (ws) => {console.log("[服务器]:连接成功");ws.send(`[websocket云端]您已经连接云端!等待数据推送~`);ws.on("message", (res) => {ws.send(`[websocket云端]收到消息:${res.toString()}`);});ws.on("close", () => {console.log("[服务器]:连接已关闭~");});
});

然后我这里编写了一个简单的demo页面

<template><div><el-button type="primary" @click="connection">创建连接</el-button><el-button type="danger" @click="close">关闭连接</el-button><el-input v-model="message" placeholder="placeholder"></el-input><el-button type="primary" @click="send">发送消息</el-button><ul><li v-for="(item, index) in messageList" :key="index">{{ item }}</li></ul></div>
</template><script>
import { WebSocketClient } from '@/utils/WebSocketClient'export default {data() {return {message: '',messageList: [],ws: null,}},methods: {connection() {if (this.ws) {this.close()}this.ws = new WebSocketClient('ws://localhost:3200')this.setupWebSocketListeners()this.ws.connect()},close() {if (this.ws) {this.ws.close()this.ws = null}},send() {if (this.ws) {this.ws.send(this.message)}},setupWebSocketListeners() {this.ws.onmessage((msg) => {this.ws.log('WebSocketClient', msg.data)this.messageList.push(msg.data)})this.ws.onopen(() => {this.ws.log('WebSocketClient', '连接已打开')})this.ws.onclose(() => {this.ws.log('WebSocketClient', '连接已关闭')})this.ws.onerror((error) => {this.ws.log('WebSocketClient', '连接错误')console.error(error)})},},mounted() {this.connection()},
}
</script>

初次连接

image-20240531100922169

消息发送

image-20240531100944165

关闭连接后,消息就无法发送了

image-20240531101029443

再次连接

image-20240531101057517

相关文章:

封装一个websocket,支持断网重连、心跳检测,拿来开箱即用

封装一个websocket&#xff0c;支持断网重连、心跳检测 代码封装 编写 WebSocketClient.js import { EventDispatcher } from ./dispatcherexport class WebSocketClient extends EventDispatcher {constructor(url) {console.log(url, urlurl)super()this.url url}// #soc…...

推荐一款开源电子签章/电子合同系统

文章目录 前言一、项目介绍二、项目地址三、技术架构四、代码结构介绍五、功能模块六、功能界面首页面手写签名面板电子印章制作数字证书生成 总结 前言 大家好&#xff01;我是智航云科技&#xff0c;今天为大家分享一个免费开源的电子签字系统。 一、项目介绍 开放签电子签…...

Qt Creator(Qt 6.6)拷贝一行

Edit - Preference - Environment&#xff1a; 可看到&#xff0c;拷贝一行的快捷键是&#xff1a; ctrl Ins...

红队内网攻防渗透:内网渗透之数据库权限提升技术

红队内网攻防渗透 1. 内网权限提升技术1.1 数据库权限提升技术1.1.1 数据库提权流程1.1.1.1 先获取到数据库用户密码1.1.1.2 利用数据库提权工具进行连接1.1.1.3 利用建立代理解决不支持外联1.1.1.4 利用数据库提权的条件及技术1.1.2 Web到Win-数据库提权-MSSQL1.1.3 Web到Win-…...

从0开始制作微信小程序

目录 前言 正文 需要事先准备的 需要事先掌握的 什么是uniapp 平台应用的分类方式 什么是TypeScript 创建项目 项目文件作用 源码地址 尾声 &#x1f52d; Hi,I’m Pleasure1234&#x1f331; I’m currently learning Vue.js,SpringBoot,Computer Security and so on.&#x1…...

Linux学习笔记:日志文件的编写

日志文件Log.hpp 日志文件的作用简单的日志文件编写 日志文件的作用 日志文件可以很好的帮我们显示出程序运行的信息,例如,进程pid,运行时间,运行状况等,通过日志记录程序的执行路径、变量值、函数调用等&#xff0c;可以帮助我们快速定位和修复代码中的错误。 简单的日志文件…...

为什么要保持方差为1

1.数值稳定性&#xff1a; 在机器学习和深度学习中&#xff0c;维持激活函数输入的方差在一个合理范围内&#xff08;如1&#xff09;是很重要的&#xff0c;这有助于防止在训练过程中发生梯度消失或梯度爆炸的问题。如果方差过大或过小&#xff0c;经过多层网络后输出结果的方…...

Wpf 使用 Prism 实战开发Day31

登录数据绑定 1.首先在LoginViewModel 登录逻辑处理类中&#xff0c;创建登录要绑定属性和命令 public class LoginViewModel : BindableBase, IDialogAware {public LoginViewModel(){ExecuteCommand new DelegateCommand<string>(Execure);}public string Title { ge…...

Linux权限提升二

#应用场景&#xff1a; 获取到Web权限或普通用户在Linux服务器上时进行的SUID&SUDO提权 SUID (Set owner User ID up on execution)是给予文件的一个特殊类型的文件权限。在Linux/Unix中&#xff0c;当一个程序运行的时候&#xff0c;程序将从登录用户处继承权限。SUID被定…...

[AI OpenAI] 推出ChatGPT Edu

一种负担得起的解决方案&#xff0c;帮助大学将AI负责任地引入校园。 我们宣布推出ChatGPT Edu&#xff0c;这是一个专为大学设计的ChatGPT版本&#xff0c;旨在负责任地向学生、教职员工、研究人员和校园运营部署AI。ChatGPT Edu由GPT-4o提供支持&#xff0c;能够跨文本和视觉…...

HTML5+CSS3回顾总结

一、HTML5新特性 1.语义化标签 <header> 头部标签<nav> 导航标签<article> 内容标签<section> 定义文档某个区域<aside> 侧边栏标签<footer> 尾部标签 2.多媒体标签 2.1视频标签vedio 》常规写法&#xff08;尽量都使用mp4&#xff0…...

AI推介-多模态视觉语言模型VLMs论文速览(arXiv方向):2024.05.01-2024.05.10

文章目录~ 1.Pseudo-Prompt Generating in Pre-trained Vision-Language Models for Multi-Label Medical Image Classification2.VLSM-Adapter: Finetuning Vision-Language Segmentation Efficiently with Lightweight Blocks3.Memory-Space Visual Prompting for Efficient …...

Python 点云生成高程模型图(DSM)

点云生成高程模型图 一、什么是DSM?二、python代码三、结果可视化一、什么是DSM? DSM(Digital Surface Model)是一种数字高程模型,通常用于描述地表地形的数字化表示。它是由一系列离散的高程数据点组成的三维地形模型,其中每个点都具有其相应的高程值。   DSM主要用于…...

[第五空间 2021]WebFTP

题目是WebFTP 通过标签可以看出git泄露(git泄露是指开发人员利用git进行版本控制) 通过网上了解WebFTP的源码账号admin 密码admin888 进去之后正常思路是我们利用/.git 在githack里面进行复现 查看log看看有没有flag 但是经过我们查询之后不是这样子 通过一段时间摸索在phpinf…...

SQL—DQL(数据查询语言)之小结

一、引言 在前面我们已经学习完了所有的关于DQL&#xff08;数据查询语言&#xff09;的基础语法块部分&#xff0c;现在对DQL语句所涉及的语法&#xff0c;以及需要注意的事项做一个简单的总结。 二、DQL语句 1、基础查询 注意&#xff1a; 基础查询的语法是&#xff1a;SELE…...

找回xmind文件办法:一切意外均可找回(误删/重启关机等)

我周三编辑完&#xff0c;周四下午评审完用例忘记保存 结果到了快乐星期五&#xff0c;由于是周五我太开心了...早上到公司后觉得电脑卡&#xff0c;直接点了重启啥都没保存啊啊啊啊啊 准备上传测试用例时才想起来我的用例找不见了&#xff01;&#xff01;&#xff01;&…...

微信小程序 npm构建+vant-weaap安装

微信小程序&#xff1a;工具-npm构建 报错 解决&#xff1a; 1、新建miniprogram文件后&#xff0c;直接进入到miniprogram目录&#xff0c;再次执行下面两个命令&#xff0c;然后再构建npm成功 npm init -y npm install express&#xff08;Node js后端Express开发&#xff…...

【LeetCode 63】 不同路径 II

1. 题目 2. 分析 这道题比较典型&#xff0c;跟最小路径和 是同样的思想。比较简单。 3. 代码 class Solution:def uniquePathsWithObstacles(self, obstacleGrid: List[List[int]]) -> int:row len(obstacleGrid)col len(obstacleGrid[-1]) dp [[0] *(col) f…...

OpenAI助手API接入-问答对自动生成

支持GPT-3.5-Turbo, GPT-4o, GPT-4-Turbo import json import openai from pathlib import Path import os client openai.OpenAI(base_urlbase_url, api_keyapi_key) file client.files.create( fileopen("H3.pdf", "rb"), purposeassistants ) …...

9. C++通过epoll+fork的方式实现高性能网络服务器

epollfork 实现高性能网络服务器 一般在服务器上&#xff0c;CPU是多核的&#xff0c;上述epoll实现方式只使用了其中的一个核&#xff0c;造成了资源的大量浪费。因此我们可以将epoll和fork结合来实现更高性能的网络服务器。 创建子进程函数–fork( ) 要了解线程我们先来了解…...

【Mac】XMind for mac(XMind思维导图)v24.04.10311软件介绍和安装教程

软件介绍 XMind for Mac是一款功能强大的思维导图软件。它具有以下主要特点&#xff1a; 1.多样化的思维导图功能&#xff1a;XMind for Mac提供了丰富的思维导图编辑功能&#xff0c;用户可以创建各种类型的思维导图&#xff0c;包括组织结构图、逻辑图、时间轴图等&#xf…...

使用 Django ORM 进行数据库操作

文章目录 创建Django项目和应用定义模型查询数据更新和删除数据总结与进阶聚合和注解跨模型查询原始SQL查询 Django是一个流行的Web应用程序框架&#xff0c;它提供了一个强大且易于使用的对象关系映射&#xff08;ORM&#xff09;工具&#xff0c;用于与数据库进行交互。在本文…...

行为型设计模式之模板模式

文章目录 概述原理结构图实现 小结 概述 模板方法模式(template method pattern)原始定义是&#xff1a;在操作中定义算法的框架&#xff0c;将一些步骤推迟到子类中。模板方法让子类在不改变算法结构的情况下重新定义算法的某些步骤。 模板方法中的算法可以理解为广义上的业…...

大泽动力车载柴油发电机的特点和优势有哪些

大泽动力车载柴油发电机具有一系列显著的特点和优势&#xff0c;以下是对其的详细介绍&#xff1a; 低噪音性能&#xff1a;大泽动力车载柴油发电机具备明显的低噪音性能&#xff0c;其噪音限值在距离机组7米处测得为70dB(A)&#xff0c;这为用户提供了一个相对安静的工作环境…...

基于 IP 的 DDOS 攻击实验

一、介绍 基于IP的分布式拒绝服务&#xff08;Distributed Denial of Service, DDoS&#xff09;攻击是一种利用大量受控设备&#xff08;通常是僵尸网络&#xff09;向目标系统发送大量请求或数据包&#xff0c;以耗尽目标系统的资源&#xff0c;导致其无法正常提供服务的攻击…...

GPT-4o如何重塑AI未来!

如何评价GPT-4o? 简介&#xff1a;最近&#xff0c;GPT-4o横空出世。对GPT-4o这一人工智能技术进行评价&#xff0c;包括版本间的对比分析、GPT-4o的技术能力以及个人感受等。 GPT-4o似乎是一个针对GPT-4模型进行优化的版本&#xff0c;它在性能、准确性、资源效率以及安全和…...

window本地域名映射修改

位置 C:\Windows\System32\drivers\etc 文件名 hosts 修改方法 复制一份到桌面 修改桌面的文件 # 前面为ip 后面为域名&#xff0c;域名-》ip的映射 127.0.0.1 link.com最后将修改后的文件保存&#xff0c;复制到C:\Windows\System32\drivers\etc替换...

【退役之重学】为什么要加入多级缓存

一、为什么 加入多级缓存是为了提高数据访问的效率和性能 二、怎么做 在多级访问系统中&#xff0c;数据首先会被存储在速度最快的 L1 缓存中&#xff0c;如果数据在 L1 缓存中未命中&#xff0c;则会继续在 L2 缓存 和 L3 缓存中查找&#xff0c;如果在所有缓存中都未命中&…...

Redis常用命令大全

目录 1、五大数据类型的基本命令 1.1 字符串 1.2 列表 1.3 哈希 1.4 集合 1.5 有序集合 2、与key相关 2.1 查看redis数据的类型 2.2 查看当前redis库中的所有key命令 3、除了五大数据类型外常见命令 3.1 键操作 3.2 服务器操作 3.3 连接操作 3.4 发布/订阅 3.5 事…...

HttpSecurity 是如何组装过滤器链的

有小伙伴们问到这个问题&#xff0c;简单写篇文章和大伙聊一下。 一 SecurityFilterChain 首先大伙都知道&#xff0c;Spring Security 里边的一堆功能都是通过 Filter 来实现的&#xff0c;无论是认证、RememberMe Login、会话管理、CSRF 处理等等&#xff0c;各种功能都是通…...