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

uniapp自定义websocket类实现socket通信、心跳检测、连接检测、重连机制

uniapp自定义websocket类实现socket通信、心跳检测、检测连接、重连机制,仿vue-socket插件功能实现发送序列号进行连接检测,发送消息时42【key,value】格式,根据后端返回数据和需要接收到的数据做nsend与onSocketMessage的修改

//使用socket类this.socket = new websocket({url: chatUrl,onOpen: (res) => {this.socket?.nsend({type: "bind",fromid: uni.getStorageSync("project_user").uid})uni.$on("message", function(data) {that.recvMsg(data)})console.log('onOpen', res)},onClose: (res) => {console.log('onClose', res)},onRdFinsh: (res) => {console.log('onRdFinsh', res)}})
import {publish,subscribe,unsubscribe
} from 'pubsub-js'
import {isArray
} from "@/utils/validate"const noop = function() {};
class Socket {//心跳检测定时器static stopTime = 0;//每25s发送报文给服务端监听连接是否正常static sendInterval = 0;//服务端监听连接异常时提示并进行socket重连static isCommunication = false;//连接中出错调用心跳检测方法的定时器static errorNr = '';//websocket已连接数static concatCount = 0;//连接后连接设备次数(用于拼接传输序号42后的数字)static sendTag = 0//pc端emit发送消息有回调函数时加入static isCallback = ["leave", "join"]//连接或断连publish相应isCallback数组内的值给客户端响应static sendKey = "";//new Socket时执行构造方法,对参数默认值进行初始化constructor({url = '',onOpen = noop,onMsg = noop,onClose = noop,onError = noop,onReload = noop,onRdFinsh = noop,maxInterValCount = 10,interValTime = 2000,...args} = {}) {this.isRconnectIng = false; //是否处于重连状态this.waiting = Promise.resolve(false); //心跳检查必须等待重连完成后this.waitDep = []; //等待时收集依赖的容器this.SocketTask = {nsend: noop,hbDetection: noop,nclose: noop,nrconnect: noop,isconnect: false,uniColse: false,maxInterValCount,interValTime,InterValCount: 0,eventPatch: null,url,onOpen,onMsg,onClose,onError,onReload,onRdFinsh,extra: args};//为对象提供连接方法this._EventDispath(this.SocketTask);//初始化websocketthis.initChat(this.SocketTask, this.SocketTask.extra);return this.SocketTask;}set CONCATCOUNT(value) {Socket.concatCount = value;if (value > 0) this._notify();}get CONCATCOUNT() {return Socket.concatCount}/*** 每25s给服务端发送一次数据,确保连接未断开*/initSendTime() {Socket.sendInterval = setInterval(() => {if (Socket.isCommunication) {uni.showToast({icon: 'none',title: '网络异常',duration: 2000})this.SocketTask.nrconnect()} else {Socket.isCommunication = truethis.SocketTask.nsend(2)}}, 25000)subscribe("number", function(msg, data) {Socket.isCommunication = false})}//销毁定时器destroySend() {clearTimeout(Socket.errorNr)clearTimeout(Socket.stopTime);clearInterval(Socket.sendInterval)unsubscribe("number")}/*** 仅供内部使用,通知所有收集到的依赖*/_notify() {for (let i = 0; i < this.waitDep.length; i++) {this.waitDep[i].call(this.SocketTask);}this.waitDep = [];}/*** 仅供内部使用,确认当前是否连接成功,收集依赖*/_chunkConnect(fn) {//没有连接时收集起来,当连接成功时开始发送命令等操作if (Socket.concatCount > 0) {fn();} else {this.waitDep.push(fn);}}/*** 仅供内部使用,事件注册*/_EventDispath({onReload} = {}) {let SocketTask = this.SocketTask;let events = {onOpen: [],onMsg: [],onClose: [],onError: [],onReload: [],onRdFinsh: [],}SocketTask.hbDetection = () => {this.hbDetection()}//适配后端websocket发送请求数据//vue-socket-io 传入的是数组,第一位为key值SocketTask.nsend = (key, value) => {let that = thisthis._chunkConnect(() => {let data = "42"//web端连接或断开连接的时候传入420 421if (Socket.isCallback.includes(key)) {//收集当前连接的命令key值,等待返回响应时传递给客户端处理逻辑Socket.sendKey = key//421 422 ··· 依次递增data += Socket.sendTagSocket.sendTag++}if (value) {data += JSON.stringify([key, value])} else {//特殊情况,当想要发送的请求不为42【key,value】格式时,key为客户端代码发送传入的值data = key + ""}uni.sendSocketMessage({//pc端emit事件有发送完毕回调函数时后端会需要有多一位数字的判断,并且返回时也会产生eg:420 -》 430// 没有回调函数时发送和接收命令前面都是42data: data,complete(e) {},})})}SocketTask.nclose = t => {this.destroySend()this._chunkConnect(() => {SocketTask.uniColse = true;uni.closeSocket();})}SocketTask.nrconnect = t => {this._chunkConnect(() => {this.waiting = new Promise(async (resolve) => {uni.closeSocket();let reloadStatus = false;try {const res = await this.initChat(SocketTask, SocketTask.extra);reloadStatus = res;} catch (e) {}onReload.call(SocketTask, reloadStatus, SocketTask);SocketTask.eventPatch.dispatchEvent('onReload', reloadStatus);resolve(reloadStatus);})})}function EventDispatcher() {this.events = events;}for (let key in events) {//绑定监听方法到EventDispatcher方法原型中EventDispatcher.prototype[key] = function(handler) {if (typeof handler != 'function') return;this.events[key].push(handler)}}//调用监听方法 监听连接状态EventDispatcher.prototype.dispatchEvent = function(type, msg) {let evenArr = this.events[type];if (evenArr.length > 0) {for (let i = 0; i < evenArr.length; i++) {evenArr[i].call(SocketTask, msg, SocketTask);}}}SocketTask.eventPatch = new EventDispatcher();}/*** 心跳检测*/async hbDetection() {const SocketTask = this.SocketTask;if (SocketTask.uniColse) {return false;}clearTimeout(Socket.stopTime);if (!SocketTask.isconnect) { //未连接则启动连接if (SocketTask.maxInterValCount > SocketTask.InterValCount) {Socket.stopTime = setTimeout(async () => {try {const R_result = await this.waiting;if (R_result) return;this.isRconnectIng = true;const openResult = await this.initChat(SocketTask, SocketTask.extra);if (openResult) {SocketTask.InterValCount++;return;}return this.hbDetection();} catch (e) {return this.hbDetection();}}, SocketTask.interValTime)} else {SocketTask.onRdFinsh.call(SocketTask, SocketTask.maxInterValCount, SocketTask);SocketTask.eventPatch.dispatchEvent('onRdFinsh', SocketTask.maxInterValCount);}}}/*** websocket监听事件*/SocketEvents({onOpen,onMsg,onClose,onError,onReload,} = {}) {return new Promise((resolve, reject) => {const SocketTask = this.SocketTask;uni.onSocketOpen(res => {this.CONCATCOUNT += 1;this.isRconnectIng = false;SocketTask.isconnect = true;Socket.sendTag = 0Socket.sendKey = ""SocketTask.InterValCount = 0;SocketTask.uniColse = false;resolve(true);this.initSendTime()onOpen.call(SocketTask, res, SocketTask);SocketTask.eventPatch.dispatchEvent('onOpen', res)})//适配服务器端返回的消息格式uni.onSocketMessage(msg => {let serialNumber = 0let arrayIndex = msg.data.indexOf("[")let objIndex = msg.data.indexOf("{")//判断返回值是纯数字或json格式let dataStart = arrayIndex != -1 && objIndex != -1 ?(arrayIndex < objIndex ? arrayIndex : objIndex) :(arrayIndex == -1 ? objIndex : arrayIndex)if (dataStart == -1) {serialNumber = msg.data.substring(0)publish("number", serialNumber)} else {serialNumber = msg.data.substring(0, dataStart)let jsonData = JSON.parse(msg.data.substring(dataStart))//判断是否为连接事件if (serialNumber == `43${Socket.sendTag - 1}`) {publish(Socket.sendKey, jsonData[0])} else if (isArray(jsonData)) {publish(jsonData[0], jsonData[1])}}onMsg.call(SocketTask, msg, SocketTask);SocketTask.eventPatch.dispatchEvent('onMsg', msg)})uni.onSocketClose(async err => {this.destroySend()SocketTask.isconnect = false;SocketTask.InterValCount = 0;//微信小程序 连接失败会自动关闭连接,返回false给心跳监测方法resolve(false);if (!this.isRconnectIng) {this.hbDetection();}onClose.call(SocketTask, err, SocketTask);SocketTask.eventPatch.dispatchEvent('onClose', err);})uni.onSocketError(err => {this.destroySend()Socket.errorNr = setTimeout(() => {this.hbDetection()}, 3000)onError.call(SocketTask, err, SocketTask);SocketTask.eventPatch.dispatchEvent('onError', err)})})}/*** 开始初始化chat*/initChat({url,onOpen,onMsg,onClose,onError,onReload} = {}, args) {return new Promise(async (resolve, reject) => {try {await this.connectSocket(url, args);let res = await this.SocketEvents({onOpen,onMsg,onClose,onError,onReload,})resolve(res);} catch (e) {console.log('initChat', e)reject();}})}/*** 连接webSocket*/connectSocket(url, args) {return new Promise((resolve, reject) => {uni.connectSocket({url,success: () => {resolve();},fail: err => {reject();},...args})})}
}
export default Socket

相关文章:

uniapp自定义websocket类实现socket通信、心跳检测、连接检测、重连机制

uniapp自定义websocket类实现socket通信、心跳检测、检测连接、重连机制&#xff0c;仿vue-socket插件功能实现发送序列号进行连接检测&#xff0c;发送消息时42【key,value】格式&#xff0c;根据后端返回数据和需要接收到的数据做nsend与onSocketMessage的修改 //使用socket…...

Hive UDTF之explode函数、Lateral View侧视图

Hive UDTF之explode函数 Hive 中的 explode() 函数是一种用于处理数组类型数据的 User-Defined Table-Generating Function (UDTF)。它将数组拆分成多行&#xff0c;每个数组元素对应生成的一行数据。这在处理嵌套数据结构时非常有用&#xff0c;例如处理 JSON 格式的数据。 …...

智慧公厕打造智慧城市新标杆

公共厕所作为城市基础设施的重要组成部分&#xff0c;直接关系到市民的生活品质和城市形象。传统的公厕管理方式存在着许多问题&#xff0c;如环境脏乱、清洁不及时等&#xff0c;给市民带来了诸多不便和不满。而智慧公厕作为一种全新的管理模式&#xff0c;通过物联网、大数据…...

字节发布文生图模型PuLID:高效身份ID特征定制,单张图像克隆AI虚拟分身

前言 字节研究团队近日提出了一种新型的文生图身份ID定制方法PuLID(Pure and Lightning ID Customization)。相较于传统的微调方法&#xff0c;PuLID无需复杂的参数优化就可以实现高效的身份ID定制&#xff0c;且能最大程度减少对原始模型行为的干扰。 PuLID是通过将轻量级的…...

SpringBoot启动流程分析之创建SpringApplication对象(一)

SpringBoot启动流程分析之创建SpringApplication对象(一) 目录&#xff1a; 文章目录 SpringBoot启动流程分析之创建SpringApplication对象(一)1、SpringApplication的构造方法1.1、推断应用程序类型1.2、设置Initializers1.3、设置Listener1.4、推断main方法所在类 流程分析…...

SSH简介 特点以及作用

引言 SSH&#xff08;Secure Shell&#xff09;是一种用于安全远程访问和数据传输的网络协议。它提供了一种安全的机制&#xff0c;使得用户可以在不安全的网络中安全地进行远程登录、命令执行和文件传输。SSH通过加密技术和认证机制来保护数据的安全性&#xff0c;防止数据在…...

MQTT服务搭建及python使用示例

1、MQTT协议 1.1、MQTT介绍 MQTT&#xff08;Message Queuing Telemetry Transport&#xff09;是一种轻量级的、基于发布/订阅模式的通信协议&#xff0c;通常用于物联网设备之间的通讯。它具有低带宽、低功耗和开放性等特点&#xff0c;适合在网络带宽有限或者网络连接不稳定…...

Ubuntu如何设置中文输入法

概述 Ubuntu 是一个基于 Debian 构建的开源操作系统&#xff0c;拥有广泛的用户群体和强大的社区支持。是免费、开源的操作系统。被设计为一个适用于个人电脑、服务器和云平台的通用操作系统。Ubuntu的目标是提供一个稳定、易于使用和免费的操作系统&#xff0c;以促进人们在计…...

PostgreSQL的pg_dump和 pg_dumpall 异同点

PostgreSQL的pg_dump和 pg_dumpall 异同点 基础信息 OS版本&#xff1a;Red Hat Enterprise Linux Server release 7.9 (Maipo) DB版本&#xff1a;16.2 pg软件目录&#xff1a;/home/pg16/soft pg数据目录&#xff1a;/home/pg16/data 端口&#xff1a;5777pg_dump 和 pg_dum…...

【Ping】Windows 网络延迟测试 ping 、telnet、tcping 工具

ping 命令 属于网络层的ICMP协议&#xff0c;只能检查 IP 的连通性或网络连接速度&#xff0c; 无法检测IP的端口状态。 telnet telnet命令&#xff0c;属于应用层的协议&#xff0c;用于远程登录&#xff0c;也可用于检测IP的端口状态。但是功能有限&#xff0c;只能检测一时…...

DuDuTalk:4G桌面拾音设备在银行网点服务场景的应用价值

随着科技的飞速发展&#xff0c;银行业也在不断地寻求创新以提高服务质量和效率。在这个过程中&#xff0c;4G桌面拾音设备作为一种新型的智能设备&#xff0c;其在银行网点服务场景中的应用价值逐渐凸显出来。本文将从多个角度探讨4G桌面拾音设备在银行网点服务场景的应用价值…...

QT 设置窗口不透明度

在窗口作为子窗口时&#xff0c;setWindowOpacity设置窗口的不透明度可能会失效。 QGraphicsOpacityEffect *opacityEffect new QGraphicsOpacityEffect(this); opacityEffect->setOpacity(1.0); this->setGraphicsEffect(opacityEffect);// 创建属性动画对象&#xff…...

如何在Python中实现文本相似度比较?

在Python中实现文本相似度比较可以通过多种方法&#xff0c;每种方法都有其适用场景和优缺点。以下是一些常见的文本相似度比较方法&#xff1a; 1. 余弦相似度&#xff08;Cosine Similarity&#xff09; 余弦相似度是通过计算两个向量之间夹角的余弦值来确定它们之间的相似…...

韩顺平0基础学Java——第7天

p110-p154 控制结构&#xff08;第四章&#xff09; 多分支 if-elseif-else import java.util.Scanner; public class day7{public static void main(String[] args) {Scanner myscanner new Scanner(System.in);System.out.println("input your score?");int s…...

性能远超GPT-4!谷歌发布Med-Gemini医疗模型;李飞飞首次创业瞄准空间智能;疫苗巨头联合OpenAl助力AI医疗...

AI for Science 企业动态速览—— * 谷歌 Med-Gemini 医疗 AI 模型性能远超 GPT-4 * 斯坦福李飞飞首次创业瞄准「空间智能」 * 疫苗巨头 Moderna 与 OpenAl 达成合作 * 美国能源部推动 AI 在清洁能源领域的应用 * 美年健康荣获「2024福布斯中国人工智能创新场景应用企业TOP10」…...

中国科技大航海时代,“掘金”一带一路

文&#xff5c;白 鸽 编&#xff5c;王一粟 “这不就是90年代的内地吗&#xff1f;” 在深度考察完沙特市场后&#xff0c;华盛集团联合创始人兼CEO张霆对镜相工作室感慨道。 在张霆看来&#xff0c;沙特落后的基建&#xff08;意味着大量创新空间&#xff09;、刚刚开放…...

ffmpeg7.0 flv支持hdr

ffmpeg7.0 flv支持hdr 自从ffmpeg6.0应用enhance rtmp支持h265/av1的flv格式后&#xff0c;7.0迎来了flv的hdr能力。本文介绍ffmpeg7.0如何支持hdr in flv。 如果对enhance rtmp如何支持h265不了解&#xff0c;推荐详解Enhanced-RTMP支持H.265 1. enhance rtmp关于hdr 文档…...

【教程】极简Python接入免费语音识别API

转载请注明出处&#xff1a;小锋学长生活大爆炸[xfxuezhagn.cn] 如果本文帮助到了你&#xff0c;请不吝给个[点赞、收藏、关注]哦~ 安装库&#xff1a; pip install SpeechRecognition 使用方法&#xff1a; import speech_recognition as srr sr.Recognizer() harvard sr…...

详解typora配置亚马逊云科技Amazon S3图床

欢迎免费试用亚马逊云科技产品&#xff1a;https://mic.anruicloud.com/url/1333 当前有很多不同的博客社区&#xff0c;不同的博客社区使用的编辑器也不尽相同&#xff0c;大概可以分为两种&#xff0c;一种是markdown格式&#xff0c;另外一种是富文本格式。例如华为云开发者…...

Python sqlite3库 实现 数据库基础及应用 输入地点,可输出该地点的爱国主义教育基地名称和批次的查询结果。

目录 【第11次课】实验十数据库基础及应用1-查询 要求: 提示: 运行结果&#xff1a; 【第11次课】实验十数据库基础及应用1-查询 声明&#xff1a;著作权归作者所有。商业转载请联系作者获得授权&#xff0c;非商业转载请注明出处。 1.简答题 数据库文件Edu_Base.db&#…...

(LeetCode 每日一题) 3442. 奇偶频次间的最大差值 I (哈希、字符串)

题目&#xff1a;3442. 奇偶频次间的最大差值 I 思路 &#xff1a;哈希&#xff0c;时间复杂度0(n)。 用哈希表来记录每个字符串中字符的分布情况&#xff0c;哈希表这里用数组即可实现。 C版本&#xff1a; class Solution { public:int maxDifference(string s) {int a[26]…...

接口测试中缓存处理策略

在接口测试中&#xff0c;缓存处理策略是一个关键环节&#xff0c;直接影响测试结果的准确性和可靠性。合理的缓存处理策略能够确保测试环境的一致性&#xff0c;避免因缓存数据导致的测试偏差。以下是接口测试中常见的缓存处理策略及其详细说明&#xff1a; 一、缓存处理的核…...

iOS 26 携众系统重磅更新,但“苹果智能”仍与国行无缘

美国西海岸的夏天&#xff0c;再次被苹果点燃。一年一度的全球开发者大会 WWDC25 如期而至&#xff0c;这不仅是开发者的盛宴&#xff0c;更是全球数亿苹果用户翘首以盼的科技春晚。今年&#xff0c;苹果依旧为我们带来了全家桶式的系统更新&#xff0c;包括 iOS 26、iPadOS 26…...

<6>-MySQL表的增删查改

目录 一&#xff0c;create&#xff08;创建表&#xff09; 二&#xff0c;retrieve&#xff08;查询表&#xff09; 1&#xff0c;select列 2&#xff0c;where条件 三&#xff0c;update&#xff08;更新表&#xff09; 四&#xff0c;delete&#xff08;删除表&#xf…...

【Linux】C语言执行shell指令

在C语言中执行Shell指令 在C语言中&#xff0c;有几种方法可以执行Shell指令&#xff1a; 1. 使用system()函数 这是最简单的方法&#xff0c;包含在stdlib.h头文件中&#xff1a; #include <stdlib.h>int main() {system("ls -l"); // 执行ls -l命令retu…...

连锁超市冷库节能解决方案:如何实现超市降本增效

在连锁超市冷库运营中&#xff0c;高能耗、设备损耗快、人工管理低效等问题长期困扰企业。御控冷库节能解决方案通过智能控制化霜、按需化霜、实时监控、故障诊断、自动预警、远程控制开关六大核心技术&#xff0c;实现年省电费15%-60%&#xff0c;且不改动原有装备、安装快捷、…...

蓝牙 BLE 扫描面试题大全(2):进阶面试题与实战演练

前文覆盖了 BLE 扫描的基础概念与经典问题蓝牙 BLE 扫描面试题大全(1)&#xff1a;从基础到实战的深度解析-CSDN博客&#xff0c;但实际面试中&#xff0c;企业更关注候选人对复杂场景的应对能力&#xff08;如多设备并发扫描、低功耗与高发现率的平衡&#xff09;和前沿技术的…...

c++ 面试题(1)-----深度优先搜索(DFS)实现

操作系统&#xff1a;ubuntu22.04 IDE:Visual Studio Code 编程语言&#xff1a;C11 题目描述 地上有一个 m 行 n 列的方格&#xff0c;从坐标 [0,0] 起始。一个机器人可以从某一格移动到上下左右四个格子&#xff0c;但不能进入行坐标和列坐标的数位之和大于 k 的格子。 例…...

数据链路层的主要功能是什么

数据链路层&#xff08;OSI模型第2层&#xff09;的核心功能是在相邻网络节点&#xff08;如交换机、主机&#xff09;间提供可靠的数据帧传输服务&#xff0c;主要职责包括&#xff1a; &#x1f511; 核心功能详解&#xff1a; 帧封装与解封装 封装&#xff1a; 将网络层下发…...

学习STC51单片机32(芯片为STC89C52RCRC)OLED显示屏2

每日一言 今天的每一份坚持&#xff0c;都是在为未来积攒底气。 案例&#xff1a;OLED显示一个A 这边观察到一个点&#xff0c;怎么雪花了就是都是乱七八糟的占满了屏幕。。 解释 &#xff1a; 如果代码里信号切换太快&#xff08;比如 SDA 刚变&#xff0c;SCL 立刻变&#…...