当前位置: 首页 > 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&#…...

深度研究报告:对波普尔科学史观的批判性剖析——从“爱因斯坦推翻牛顿”到“贾子理论”的解绑革命

深度研究报告&#xff1a;对波普尔科学史观的批判性剖析——从“爱因斯坦推翻牛顿”到“贾子理论”的解绑革命 摘要 本报告深度剖析了针对波普尔科学史观的核心批判。指控波普尔通过编造“爱因斯坦推翻牛顿”的虚假叙事&#xff0c;将理论间的边界扩展恶意曲解为颠覆性革命&a…...

5分钟搞定明日方舟重复劳动:MAA自动化助手完整攻略

5分钟搞定明日方舟重复劳动&#xff1a;MAA自动化助手完整攻略 【免费下载链接】MaaAssistantArknights 《明日方舟》小助手&#xff0c;全日常一键长草&#xff01;| A one-click tool for the daily tasks of Arknights, supporting all clients. 项目地址: https://gitcod…...

开关电源CCM与DCM模式选择指南:从理论到实践

1. 开关电源CCM与DCM模式基础解析 第一次接触开关电源设计时&#xff0c;我被CCM和DCM这两个专业术语搞得一头雾水。直到亲手烧坏三个MOS管后&#xff0c;才真正理解它们的区别。简单来说&#xff0c;CCM&#xff08;连续导通模式&#xff09;就像高速公路上的车流&#xff0c;…...

从‘单向导电’到‘电流引导’:重新理解GPIO保护二极管的真实工作模式

从‘单向导电’到‘电流引导’&#xff1a;重新理解GPIO保护二极管的真实工作模式 在嵌入式硬件设计中&#xff0c;GPIO保护二极管常被简化为"防反接开关"的角色&#xff0c;这种认知掩盖了其作为动态电流路径选择器的本质。当我们用阻抗网络和分流原理重新审视这个经…...

Superset开发环境搭建指南:从零开始本地部署

1. 认识Superset&#xff1a;为什么选择它&#xff1f; Superset是Apache基金会旗下的开源数据可视化工具&#xff0c;用Python编写&#xff0c;基于Flask框架。我第一次接触它是在2018年&#xff0c;当时团队需要替换昂贵的商业BI工具。经过对比测试&#xff0c;Superset的响…...

Kettle8.2转换组件实战:利用增加序列实现Excel数据自动编号

1. 为什么需要给Excel数据自动编号&#xff1f; 每次处理Excel数据时&#xff0c;最头疼的就是要给每行数据加个序号。手动添加不仅效率低&#xff0c;还容易出错。上周我帮市场部处理3000多条客户数据&#xff0c;就因为手工编号搞错顺序&#xff0c;差点引发数据混乱。这时候…...

5分钟搞定抖音无水印下载:douyin-downloader终极指南

5分钟搞定抖音无水印下载&#xff1a;douyin-downloader终极指南 【免费下载链接】douyin-downloader A practical Douyin downloader for both single-item and profile batch downloads, with progress display, retries, SQLite deduplication, and browser fallback suppor…...

HIC数据预处理实战:Hicup、ALLHiC和juicer三大工具保姆级教程

HIC数据预处理实战&#xff1a;Hicup、ALLHiC和juicer三大工具保姆级教程 Hi-C技术作为三维基因组学研究的重要工具&#xff0c;其数据预处理环节直接决定了后续分析的可靠性。面对Hicup、ALLHiC和juicer这三款主流工具&#xff0c;科研新手常陷入选择困境。本文将带您深入实战…...

5个技巧,让Qwen-Image-2512-SDNQ帮你生成电商级产品图

5个技巧&#xff0c;让Qwen-Image-2512-SDNQ帮你生成电商级产品图 1. 为什么选择Qwen-Image-2512-SDNQ生成产品图 在电商运营中&#xff0c;高质量的产品图片直接影响转化率。传统摄影需要专业设备、场地和后期处理&#xff0c;成本高且周期长。Qwen-Image-2512-SDNQ模型通过…...

Nunchaku FLUX.1 CustomV3批量处理技巧:高效生成1000+图像的方法

Nunchaku FLUX.1 CustomV3批量处理技巧&#xff1a;高效生成1000图像的方法 1. 引言 如果你正在使用Nunchaku FLUX.1 CustomV3生成图像&#xff0c;可能会遇到这样的困扰&#xff1a;每次只能生成几张图片&#xff0c;想要大批量产出内容时&#xff0c;需要反复手动操作&…...