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

SpringBoot-17-MyBatis动态SQL标签之常用标签

文章目录 1 代码1.1 实体User.java1.2 接口UserMapper.java1.3 映射UserMapper.xml1.3.1 标签if1.3.2 标签if和where1.3.3 标签choose和when和otherwise1.4 UserController.java2 常用动态SQL标签2.1 标签set2.1.1 UserMapper.java2.1.2 UserMapper.xml2.1.3 UserController.ja…...

铭豹扩展坞 USB转网口 突然无法识别解决方法

当 USB 转网口扩展坞在一台笔记本上无法识别,但在其他电脑上正常工作时,问题通常出在笔记本自身或其与扩展坞的兼容性上。以下是系统化的定位思路和排查步骤,帮助你快速找到故障原因: 背景: 一个M-pard(铭豹)扩展坞的网卡突然无法识别了,扩展出来的三个USB接口正常。…...

eNSP-Cloud(实现本地电脑与eNSP内设备之间通信)

说明&#xff1a; 想象一下&#xff0c;你正在用eNSP搭建一个虚拟的网络世界&#xff0c;里面有虚拟的路由器、交换机、电脑&#xff08;PC&#xff09;等等。这些设备都在你的电脑里面“运行”&#xff0c;它们之间可以互相通信&#xff0c;就像一个封闭的小王国。 但是&#…...

8k长序列建模,蛋白质语言模型Prot42仅利用目标蛋白序列即可生成高亲和力结合剂

蛋白质结合剂&#xff08;如抗体、抑制肽&#xff09;在疾病诊断、成像分析及靶向药物递送等关键场景中发挥着不可替代的作用。传统上&#xff0c;高特异性蛋白质结合剂的开发高度依赖噬菌体展示、定向进化等实验技术&#xff0c;但这类方法普遍面临资源消耗巨大、研发周期冗长…...

鸿蒙中用HarmonyOS SDK应用服务 HarmonyOS5开发一个医院查看报告小程序

一、开发环境准备 ​​工具安装​​&#xff1a; 下载安装DevEco Studio 4.0&#xff08;支持HarmonyOS 5&#xff09;配置HarmonyOS SDK 5.0确保Node.js版本≥14 ​​项目初始化​​&#xff1a; ohpm init harmony/hospital-report-app 二、核心功能模块实现 1. 报告列表…...

【2025年】解决Burpsuite抓不到https包的问题

环境&#xff1a;windows11 burpsuite:2025.5 在抓取https网站时&#xff0c;burpsuite抓取不到https数据包&#xff0c;只显示&#xff1a; 解决该问题只需如下三个步骤&#xff1a; 1、浏览器中访问 http://burp 2、下载 CA certificate 证书 3、在设置--隐私与安全--…...

Android15默认授权浮窗权限

我们经常有那种需求&#xff0c;客户需要定制的apk集成在ROM中&#xff0c;并且默认授予其【显示在其他应用的上层】权限&#xff0c;也就是我们常说的浮窗权限&#xff0c;那么我们就可以通过以下方法在wms、ams等系统服务的systemReady()方法中调用即可实现预置应用默认授权浮…...

多种风格导航菜单 HTML 实现(附源码)

下面我将为您展示 6 种不同风格的导航菜单实现&#xff0c;每种都包含完整 HTML、CSS 和 JavaScript 代码。 1. 简约水平导航栏 <!DOCTYPE html> <html lang"zh-CN"> <head><meta charset"UTF-8"><meta name"viewport&qu…...

iOS性能调优实战:借助克魔(KeyMob)与常用工具深度洞察App瓶颈

在日常iOS开发过程中&#xff0c;性能问题往往是最令人头疼的一类Bug。尤其是在App上线前的压测阶段或是处理用户反馈的高发期&#xff0c;开发者往往需要面对卡顿、崩溃、能耗异常、日志混乱等一系列问题。这些问题表面上看似偶发&#xff0c;但背后往往隐藏着系统资源调度不当…...

搭建DNS域名解析服务器(正向解析资源文件)

正向解析资源文件 1&#xff09;准备工作 服务端及客户端都关闭安全软件 [rootlocalhost ~]# systemctl stop firewalld [rootlocalhost ~]# setenforce 0 2&#xff09;服务端安装软件&#xff1a;bind 1.配置yum源 [rootlocalhost ~]# cat /etc/yum.repos.d/base.repo [Base…...