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

基于Pinia的WebSocket管理与优化实践(实现心跳重连机制,异步发送)

WebSocket作为一种全双工通信协议,允许服务器和客户端之间建立持久的连接,提供了比传统HTTP请求更为高效的数据交换方式。本文将探讨如何使用Pinia状态管理库在Vue应用中优雅地管理和优化WebSocket连接,以实现稳定、高效的实时数据传输。

环境与依赖

  • 环境:Vue.js项目
  • 依赖:Pinia (pnpm install pinia) 和 vant (pnpm install vant)

项目结构与初始化

在项目中,我们创建了一个名为useWebsocketStore的Pinia store,专门用于管理WebSocket相关的状态和行为。该store包含了一系列关键的状态变量和动作,旨在简化WebSocket的连接、消息处理、心跳机制以及重连策略。

WebSocket Store设计

核心状态

  • socket: WebSocket实例。
  • ConnectSuccess: 连接成功标志。
  • messageHandlers: 存储注册的消息处理器数组。
  • deviceIP: 设备的IP地址。
  • reconnectNum: 重连次数。
  • heartbeatMessage: 心跳消息内容。
  • strWs: 发送消息的字符串形式。
  • sendNum: 发送消息计数。
  • messageNum: 接收消息计数。
  • message: 最近接收的消息内容。
    动作详解
  • connectWs: 初始化WebSocket连接,包括建立连接、监听事件、启动心跳,并提供Promise接口确保异步操作的完成。
  • registerMessageHandler & unregisterMessageHandler:允许外部组件注册或注销消息处理器,实现了插拔式的事件处理机制。
  • handleMessageFromWebSocket: 处理从WebSocket接收到的消息,更新内部状态并调用所有注册的消息处理器。
  • handleClose: WebSocket关闭时的处理逻辑,包括重连尝试、状态重置及错误通知。
  • **`sendMessage: 发送消息至WebSocket,包含基本的发送逻辑。
  • sendMessageWithRetry: 异步发送消息,自动处理连接重试,增强了消息发送的健壮性。
  • **sendHeartbeat: 发送心跳消息,维护连接活性。
  • **startHeartbeat&stopHeartbeat: 控制心跳定时器的启动与停止,确保资源的有效利用。

为什么需要心跳机制

心跳机制(Heartbeat Mechanism)主要用于保持网络连接的活跃状态,尤其是在TCP/IP连接中,如HTTP长轮询、WebSocket、TCP长连接等场景中。它通过周期性地发送小量数据(通常称为心跳包)来确认连接的双方仍然存活,进而避免因网络层的超时或中间代理(如负载均衡器、防火墙)的会话超时而导致的连接意外断开。

useWebsocketStore.js

import { defineStore } from 'pinia'import { showToast } from 'vant'export const useWebsocketStore = defineStore('websocket', {state: () => ({socket: null,ConnectSuccess: false,// 新增一个数组用于存储注册的处理器messageHandlers: [],deviceIP: null,reconnectNum: 0,heartbeatMessage: JSON.stringify({ cmd: '1111' }), // 心跳消息内容strWs: null,sendNum: 0,messageNum: 0,message: 0}),getters: {},actions: {async connectWs(deviceIP) {if (!this.socket && !this.ConnectSuccess) {console.log('connectWs', deviceIP)this.deviceIP = deviceIPthis.socket = new WebSocket(deviceIP)// this.socket.onopen = this.handleOpenthis.socket.onmessage = this.handleMessageFromWebSocketthis.socket.onclose = this.handleClose// this.socket.onerror = this.handleErrorreturn new Promise((resolve, reject) => {this.socket.onopen = (event) => {console.log('WebSocket 连接已建立', event)this.ConnectSuccess = truethis.startHeartbeat()resolve()}this.socket.onerror = (event) => {console.error('WebSocket 连接错误', event)this.ConnectSuccess = falsereject(event)}})}},// 新增方法用于注册消息处理器registerMessageHandler(handler) {this.messageHandlers.push(handler)},// 新增方法用于移除消息处理器unregisterMessageHandler(handler) {this.messageHandlers = this.messageHandlers.filter((h) => h !== handler)},//handleMessageFromWebSocket(event) {const message = JSON.parse(event.data)console.log('消息', message)this.message = message.cmdthis.messageNum += 1// 调用所有注册的处理器// console.log(message)this.messageHandlers.forEach((handler) => handler(message))},handleOpen(event) {console.log('WebSocket 连接已建立', event)if (event.target.readyState === 1) {this.ConnectSuccess = true}},handleClose(event) {console.error('WebSocket 关闭:', event)this.socket = nullthis.ConnectSuccess = falsethis.sendNum = 0this.messageNum = 0this.stopHeartbeat()// 添加自动重连逻辑this.reconnectWs().then(() => {this.ConnectSuccess = trueshowToast('WebSocket 重连成功')}).catch((error) => {this.ConnectSuccess = falseshowToast('最终重连失败', error)})},handleError(error) {console.error('WebSocket 错误:', error)this.ConnectSuccess = false},async reconnectWs() {return new Promise(async (resolve, reject) => {this.reconnectNum++try {console.log(`尝试重新连接... (${this.reconnectNum})`)await this.connectWs(this.deviceIP)if (this.socket && this.ConnectSuccess) {resolve() // 连接成功,停止重试} else {throw new Error('连接失败')}} catch (error) {this.ConnectSuccess = falseconsole.log(`重连WebSocket失败,稍后重试... (${this.reconnectNum})`)reject()}})},sendMessage(message) {// 发送消息逻辑...if (this.socket.readyState === WebSocket.OPEN) {// showToast('确定发送', message)this.strWs = JSON.parse(message).cmdthis.sendNum += 1this.socket.send(message)} else {// 如果在此之后仍然无法发送,可以选择抛出错误或继续等待(根据需求)showToast('WebSocket 尚未连接')console.error('即使重试后,WebSocket仍无法发送消息')}},// 在actions中添加一个新的异步发送方法async sendMessageWithRetry(message) {if (!this.ConnectSuccess) {// 如果连接未建立,尝试重新连接try {await this.reconnectWs()} catch (error) {console.error('尝试重新连接WebSocket失败', error)throw error}}this.sendMessage(message)},// 发送心跳消息的方法sendHeartbeat() {this.sendMessageWithRetry(this.heartbeatMessage)},// 启动心跳定时器startHeartbeat() {this.heartbeatInterval = setInterval(() => {this.sendHeartbeat()}, 5000) // 每隔3秒发送一次心跳},// 如果需要在适当的时候清理心跳定时器,比如在断开连接时stopHeartbeat() {if (this.heartbeatInterval) {clearInterval(this.heartbeatInterval)this.heartbeatInterval = null}}}
})

.vue 文件中使用

useWebsocket.connectWs(deviceIP) 连接socket 只需要连接一次,可以放在main.js 里面初始化的时候连接

<script setup>
import {  onMounted, onUnmounted,  } from 'vue'import { useWebsocketStore } from '@/stores/useWebsocketStore'
const useWebsocket = useWebsocketStore()const deviceIP='ws:192.168.89'
const handleMessage= (message)=>{// 外部处理消息逻辑
}
const init = () => {useWebsocket.connectWs(deviceIP) // useWebsocket.registerMessageHandler(handleMessage)
}
init()onUnmounted(() => {// 组件卸载时移除消息处理器useWebsocket.unregisterMessageHandler(handleMessage)})

相关文章:

基于Pinia的WebSocket管理与优化实践(实现心跳重连机制,异步发送)

WebSocket作为一种全双工通信协议&#xff0c;允许服务器和客户端之间建立持久的连接&#xff0c;提供了比传统HTTP请求更为高效的数据交换方式。本文将探讨如何使用Pinia状态管理库在Vue应用中优雅地管理和优化WebSocket连接&#xff0c;以实现稳定、高效的实时数据传输。 环境…...

Perl词法作用域:自定义编程环境的构建术

&#x1f3ad; Perl词法作用域&#xff1a;自定义编程环境的构建术 在Perl编程中&#xff0c;词法作用域&#xff08;lexical scoping&#xff09;是一种控制变量可见性的方式&#xff0c;它允许变量在特定的作用域内可见&#xff0c;从而避免变量名的冲突。Perl提供了灵活的机…...

vscode使用ssh连接远程服务器

开工啦 vscode连接远程服务器&#xff08;傻瓜式教学&#xff09; 正常根据上面文章的步骤就可以连接了 报错可以尝试的文章&#xff1a; VScode通过remote ssh连接虚拟机 & 报错过程试图写入的管道不存在&#xff08;已解决&#xff09; vscode remote ssh linux[血泪…...

linux 常用和不那么常用命令记录02 磁盘占用

常用的磁盘相关命令 du 有的时候我们想要查询一个文件所占用的磁盘空间大小&#xff0c;可以使用du命令来查看 命令 配置 参数 du [options] [files or directories]-h&#xff1a;以人类可读的格式显示输出&#xff08;例如 KB、MB、GB&#xff09;。 -s&#xf…...

mybatis日志记录方案

首先对指定表进行监控 对表进行监控,那么就要使用的是statementInterceptor 拦截器 使用拦截器那么就要写intercepts写拦截条件进行拦截 监控只对与增删改 查询不进行监控 对于字段的监控,是谁修改了字段,那么就进行报警,或者提醒 消息提醒使用钉钉机器人进行消息提醒 P…...

【LeetCode】最长连续序列

目录 一、题目二、解法完整代码 一、题目 给定一个未排序的整数数组 nums &#xff0c;找出数字连续的最长序列&#xff08;不要求序列元素在原数组中连续&#xff09;的长度。 请你设计并实现时间复杂度为 O(n) 的算法解决此问题。 示例 1&#xff1a; 输入&#xff1a;nu…...

Windows下终端Kafka指令常用操作

1、创建Topic kafka-topics.bat --create --bootstrap-server localhost:9092 --replication-factor 1 --partitions 1 --topic test 2、查看Topic列表 kafka-topics.bat --list --bootstrap-server localhost:9092 3、设置Topic最大消息大小 kafka-topics.bat --bootstrap-s…...

QT---lineEdit相关信号

1.returnPressed信号 connect(ui.lineEdit_passWord, &QLineEdit::returnPressed, []() { // 输入密码回车后&#xff0c;调用校验密码接口ui.lineEdit_passWord->clearFocus(); //失去焦点on_param_confirmBtn_clicked();});2.输入后失去焦点才获取编辑框内新信息 参…...

基于vue的地图特效(飞线和标注)

这段代码的主要功能是在页面加载完成后&#xff0c;初始化一个 echarts 地图图表&#xff0c;并配置了相关的地理数据、散点数据、线条数据以及样式效果&#xff0c;最后在指定的 div 元素中进行展示。 需要再vue中的框架实现&#xff0c;不能单独直接运行。 标注 type: effe…...

生物环保技术有哪些缺点或者局限性呢

生物环保技术&#xff0c;作为一种利用生物学原理和技术来处理环境污染的方法&#xff0c;虽然具有绿色环保、高效节能等优点&#xff0c;但也存在一些缺点和局限性。以下是对这些缺点和局限性的详细分析&#xff1a; 一、受环境因素影响大 生物环保技术的效果往往受到环境因…...

我被手机所伤,竟如此憔悴。

临睡前&#xff0c;刚刷完小视频&#xff0c;感觉好无聊。一阵阵空虚感袭来。看看时间&#xff0c;哦&#xff0c;原来我下班后一直从6点刷视频到11点。 哎&#xff0c;太空虚了&#xff0c;又马上要睡觉了&#xff0c;为什么会这么难受呢?明明我大学&#xff0c;高中&#x…...

【深度学习】第3章实验——回归模型

根据相关数据集进行回归分析 1. import statsmodels.api as sm # df.loc[:, ...] 表示选择所有行。 # df.columns ! mpg 创建一个布尔数组&#xff0c;指示哪些列不等于 mpg。 # df.loc[:, df.columns ! mpg] 选择 df 中所有行和列名不等于 mpg 的所有列。 x df.loc[:,df.col…...

MYSQL 四、mysql进阶 8(索引优化与查询优化)

都有哪些维度可以进行数据库调优&#xff1f;简言之&#xff1a; 索引失效、没有充分利用到索引——建立索引关联查询太多JOIN&#xff08;设计缺陷或不得已的需求&#xff09;——SQL优化服务器调优及各个参数设置&#xff08;缓冲、线程数等&#xff09;——调整my.cnf数据过…...

python | pyvips,一个神奇的 Python 库

本文来源公众号“python”&#xff0c;仅用于学术分享&#xff0c;侵权删&#xff0c;干货满满。 原文链接&#xff1a;pyvips&#xff0c;一个神奇的 Python 库&#xff01; 大家好&#xff0c;今天为大家分享一个神奇的 Python 库 - pyvips。 Github地址&#xff1a;https…...

STM32利用FreeRTOS实现4个led灯同时以不同的频率闪烁

在没有接触到FreeRTOS时&#xff0c;也没有想过同时叫两个或两个以上的led灯闪烁的想法&#xff0c;接触后&#xff0c;发现如果想叫两个灯同时以不同的频率闪烁&#xff0c;不能说是不可能&#xff0c;就算是做到了也要非常的麻烦。但是学习了FreeRTOS后&#xff0c;发现要想同…...

深入Laravel事件系统:创建与使用事件的指南

Laravel的事件系统是一种强大的机制&#xff0c;它允许你将应用程序的行为封装成事件&#xff0c;然后在适当的时候触发这些事件。这不仅有助于代码的解耦&#xff0c;还提高了应用程序的可维护性和可扩展性。本文将详细介绍如何在Laravel中创建和使用事件&#xff0c;包括事件…...

element-ui操作表格行内容如何获取当前行索引?

需求&#xff1a; 根据每个用户的提交次数、撤回次数&#xff0c;动态计算出实际次数&#xff0c;并且提交次数不能小于撤回次数 <template><div><el-table:data"tableData"style"width: 80%"border><el-table-columnprop"date&…...

代发考生战报:南京考场华为售前HCSP H19-411考试通过

代发考生战报&#xff1a;南京考场华为售前HCSP H19-411考试通过&#xff0c;客服给的题库非常稳定&#xff0c;考试遇到2个新题&#xff0c;剩下全是题库里的原题&#xff0c;想考的放心考吧&#xff0c;考场服务挺好&#xff0c;管理员带着做签名和一些考试说明介绍清楚&…...

【Spring Boot】Spring原理:Bean的作用域和生命周期

目录 Spring原理一. 知识回顾1.1 回顾Spring IOC1.2 回顾Spring DI1.3 回顾如何获取对象 二. Bean的作用域三. Bean的生命周期 Spring原理 一. 知识回顾 在之前IOC/DI的学习中我们也用到了Bean对象&#xff0c;现在先来回顾一下IOC/DI的知识吧&#xff01; 首先Spring IOC&am…...

MinIO:开源对象存储解决方案的领先者

MinIO:开源对象存储解决方案的领先者 MinIO 是一款开源的对象存储系统&#xff0c;致力于提供高性能、可伸缩、安全的数据存储解决方案。 官方解释&#xff1a;MinIO 是一个基于Apache License v2。0开源协议的对象存储服务。它兼容亚马逊S3云存储服务接口&#xff0c;非常适…...

golang循环变量捕获问题​​

在 Go 语言中&#xff0c;当在循环中启动协程&#xff08;goroutine&#xff09;时&#xff0c;如果在协程闭包中直接引用循环变量&#xff0c;可能会遇到一个常见的陷阱 - ​​循环变量捕获问题​​。让我详细解释一下&#xff1a; 问题背景 看这个代码片段&#xff1a; fo…...

DeepSeek 赋能智慧能源:微电网优化调度的智能革新路径

目录 一、智慧能源微电网优化调度概述1.1 智慧能源微电网概念1.2 优化调度的重要性1.3 目前面临的挑战 二、DeepSeek 技术探秘2.1 DeepSeek 技术原理2.2 DeepSeek 独特优势2.3 DeepSeek 在 AI 领域地位 三、DeepSeek 在微电网优化调度中的应用剖析3.1 数据处理与分析3.2 预测与…...

ESP32读取DHT11温湿度数据

芯片&#xff1a;ESP32 环境&#xff1a;Arduino 一、安装DHT11传感器库 红框的库&#xff0c;别安装错了 二、代码 注意&#xff0c;DATA口要连接在D15上 #include "DHT.h" // 包含DHT库#define DHTPIN 15 // 定义DHT11数据引脚连接到ESP32的GPIO15 #define D…...

三体问题详解

从物理学角度&#xff0c;三体问题之所以不稳定&#xff0c;是因为三个天体在万有引力作用下相互作用&#xff0c;形成一个非线性耦合系统。我们可以从牛顿经典力学出发&#xff0c;列出具体的运动方程&#xff0c;并说明为何这个系统本质上是混沌的&#xff0c;无法得到一般解…...

【HTTP三个基础问题】

面试官您好&#xff01;HTTP是超文本传输协议&#xff0c;是互联网上客户端和服务器之间传输超文本数据&#xff08;比如文字、图片、音频、视频等&#xff09;的核心协议&#xff0c;当前互联网应用最广泛的版本是HTTP1.1&#xff0c;它基于经典的C/S模型&#xff0c;也就是客…...

Linux 内存管理实战精讲:核心原理与面试常考点全解析

Linux 内存管理实战精讲&#xff1a;核心原理与面试常考点全解析 Linux 内核内存管理是系统设计中最复杂但也最核心的模块之一。它不仅支撑着虚拟内存机制、物理内存分配、进程隔离与资源复用&#xff0c;还直接决定系统运行的性能与稳定性。无论你是嵌入式开发者、内核调试工…...

MySQL JOIN 表过多的优化思路

当 MySQL 查询涉及大量表 JOIN 时&#xff0c;性能会显著下降。以下是优化思路和简易实现方法&#xff1a; 一、核心优化思路 减少 JOIN 数量 数据冗余&#xff1a;添加必要的冗余字段&#xff08;如订单表直接存储用户名&#xff09;合并表&#xff1a;将频繁关联的小表合并成…...

Go语言多线程问题

打印零与奇偶数&#xff08;leetcode 1116&#xff09; 方法1&#xff1a;使用互斥锁和条件变量 package mainimport ("fmt""sync" )type ZeroEvenOdd struct {n intzeroMutex sync.MutexevenMutex sync.MutexoddMutex sync.Mutexcurrent int…...

MacOS下Homebrew国内镜像加速指南(2025最新国内镜像加速)

macos brew国内镜像加速方法 brew install 加速formula.jws.json下载慢加速 &#x1f37a; 最新版brew安装慢到怀疑人生&#xff1f;别怕&#xff0c;教你轻松起飞&#xff01; 最近Homebrew更新至最新版&#xff0c;每次执行 brew 命令时都会自动从官方地址 https://formulae.…...

BLEU评分:机器翻译质量评估的黄金标准

BLEU评分&#xff1a;机器翻译质量评估的黄金标准 1. 引言 在自然语言处理(NLP)领域&#xff0c;衡量一个机器翻译模型的性能至关重要。BLEU (Bilingual Evaluation Understudy) 作为一种自动化评估指标&#xff0c;自2002年由IBM的Kishore Papineni等人提出以来&#xff0c;…...