websocket具体实践

websocket具体实践

参考:
如何使用websocket
WebSocket客户端连接不上和掉线的问题以及解决方案

    继6月份对websocket一顿了解之后,我们的项目也要上websocket了,虽然这部分不是我做,但是借此机会,我也想要尝试一下:假如是我来写这个模块,我会写成什么样呢?
抱着这样的想法,在11月份开始着手查了一些资料,打算完整地写一份前端的socket实例,一开始完全没有头绪,网上查了查大家写的都很简略的样子,达不到想要的效果,后来写小程序的时候想到可以借鉴小程序里的websocket封装,然后终于确定了类的api和基本功能。
    修改过几次后,实现的功能和流程如下:(当然我自己写的这一份只是在自己的网站里做了一些简单测试,里面肯定还有很多bug待解决的)

  • 1.0 第一版:引入scoketio客户端依赖做的,已经全面否决
  • 1.1 第二版:使用函数实现,实际使用感乱七八糟的。
  • 1.2 第三版:借鉴小程序的类封装,定义好了简单的success/fail/onError API 实现
  • 1.3 第四版:增加多场景(1、时效性强不需要重连机制,连接失败立马更换轮询场景。2、保持长连接的可重连场景),增加心跳、断线重连
  • 1.4 第五版:断线后不会发送close事件,心跳事件仍然照常发送,故取消断线重连的机制,但是检测定时器仍然保留。
    疑问:
    1. 心跳事件如果只有客户端发送保活,后端收到后不响应,会不会有什么问题?
    • 基本不会有问题,保活是为了确保正确的连接到俩端,出于服务器性能考虑可以这样做。
    1. 如果断线后没有检测到连接断开,会不会重连时多个客户端连接到同一个后端上去了,这样有办法检测吗?
    • 后端可以检测连接的websocket session,把之前的取消掉,否则可能会出现服务端发送了消息但是客户端接受不到的情况,
编写中遇到的问题:
  1. 重连需要注意把之前的连接关闭,否则就会出现内存泄漏的问题,如下图一下开了好多个连接,后端也收到好多个连接

  2. websocket和MQ消息队列有什么不同,为什么不采用MQ.
  • MQ没办法精准定位到用户,如果有多个用户需要消息,往消息队列中取消息不知道哪个才是自己的。
  • 前端获取MQ信息不像后端那么好操作易上手,而ws是html支持的API

前端代码实现如下:
后端是使用express-ws简单地建立了一个本地服务器,代码不贴了吧,网上老多了。

const READY_STATE = {CONNECTING: 'CONNECTING',OPEN: 'OPEN',CLOSING: 'CLOSING',CLOSED: 'CLOSED',0: 'CONNECTING',1: 'OPEN',2: 'CLOSING',3: 'CLOSED',
};/*** eg: new Socket('/connect',{success:(ws)=>{}, fail:(e)=>{switch(e.code){}}, onMessage:(res)=>{} })* onclose 如果允许重连则重连,不允许则直接回调fail* onerror 仅在后台发出警示,回调中不开放这个回调,一切在fail函数中处理* @param url 需要连接的ws链接,仅 /+pathname host拼接* @param success 连接成功后调用* @param fail 连接失败 除了以下code,其他为未知bug*             code=1 -> 不支持websocket*             code=2 -> 不允许重连-连接失败、允许重连-重连三次后也还是连接失败*             code=3 -> 身份验证未通过*             code=4 -> 未收到心跳事件主动断开连接*             code=5 -> (暂时不处理) 因为客户端断线 / 服务端主动断开等原因导致连接关闭后的回调* @param onMessage 收到消息的回调函数。* @param allowReConnect 允许连接失败后再重新连接而不立刻返回失败结果。(比如结果页就不需要重连,只需要第一次连接的结果,否则重连几次后,支付结果都出来了)* 连接成功后将发送身份验证,每次连接发送数据需要带上本次会话的发送时间戳(不然前端无法确定本次回复是哪次消息)* ? 如果意外在同一个页面同时创建了多个链接,前端无法检测出来,因为对象之间互相不联系,需要后端查询是否有相同用户链接,主动断开。*/
class Socket {constructor(connectUrl = '', options = {}) {this.initData(connectUrl, options);this.connect();}initData = (connectUrl, options) => {this.connectUrl = connectUrl;this.props = options;// socket连接事件this.socketOpen = false;this.socketConnecting = false;this.socketMsgQueue = []; // 待发送、发送后未收到回复 的消息队列this.maxSocketConnectCount = 3; // 最多断线重连3次this.socketConnectCount = 0; // 断线重连次数this.socketConnectTimer = null; // 断线重连定时器// 心跳事件this.heartBeatFailCount = 0; // 心跳连接失败次数this.heartBeatTimer = null; // 心跳事件定时器this.heartBeatEventCb = null; // 心跳事件回调函数,一旦回应则清空,未回应则重连或关闭连接。};/*** 建立连接* @param {string} from reconnet | undefined  默认为初始化连接,reconnet为连接失败重连*/connect = (from = 'connect') => {try {if (!window.WebSocket) {this.options.fail({ code: 1, error: '不支持' });}const ws = new WebSocket('ws://localhost:8100' + this.connectUrl);this.socketConnecting = true;// 注册ws相关事件ws.onopen = () => {console.log('success');this.ws = ws;this.socketOpen = true;this.socketConnecting = false;this.cancelReConnect();this.ping();};ws.onerror = (e) => {this.socketOpen = false;this.socketConnecting = false;console.error('ERROR:' + from + '-连接失败');};ws.onclose = () => {console.error('CLOSE:' + from + '-连接失败');this.socketOpen = false;this.cancelHeartBeat();if(this.socketConnecting){ws.close();this.socketConnecting = false;}if (this.props.allowReConnect) {this.reConnect();} else {this.props.fail?.({ code: 2, error: '连接失败' });}};} catch (error) {this.options.fail({ code: 1000, error });}};/** 取消重连 */cancelReConnect = () => {if (this.socketConnectTimer) {clearTimeout(this.socketConnectTimer);this.socketConnectTimer = null;this.socketConnectCount = 0;}};/** 重连 */reConnect = () => {if (this.socketConnectCount < this.maxSocketConnectCount) {this.socketConnectCount = this.socketConnectCount + 1;this.socketConnectTimer = setTimeout(()=>{this.connect();},1000)} else {this.socketConnectCount = 0;clearTimeout(this.socketConnectTimer);this.socketConnectTimer = null;}};onmessage = (e, cb) => {if (e.data === 'pong') {// 清空当前的心跳回调事件clearTimeout(this.heartBeatEventCb);this.heartBeatEventCb = null;}console.log('from server: ' + e.data);cb(e);};// 关闭心跳事件cancelHeartBeat = () => {clearInterval(this.heartBeatTimer);this.heartBeatTimer = null;};// 注册心跳事件ping = () => {if (this.heartBeatTimer) {this.cancelHeartBeat();}this.heartBeatTimer = setInterval(() => {this.ws.send('ping');// 向心跳事件列表push一个心跳事件,30秒发送一次,setTimeOut 10s后没有收到Pong消息则重连或关闭连接。this.heartBeatEventCb = setTimeout(()=>{this.ws.close();this.props.fail({code:4,error:'未收到心跳事件'})},1 * 10 * 1000)}, 1 * 30 * 1000);};
}export default Socket;

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/673075.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

VS无法使用万能头文件#include <bits/stdc++.h> 的解决办法

第一步在vs中打出可以使用的头文件 如#include<cmath> 点击F12转到文档 上面窗口右键找到打开所在文件夹 创建一个名字为bits的文件夹 里面创建一个text文件 // C includes used for precompiling -*- C -*-// Copyright (C) 2003-2015 Free Software Foundation, In…

【开源】JAVA+Vue.js实现开放实验室管理系统

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、研究内容2.1 实验室类型模块2.2 实验室模块2.3 实验管理模块2.4 实验设备模块2.5 实验订单模块 三、系统设计3.1 用例设计3.2 数据库设计 四、系统展示五、样例代码5.1 查询实验室设备5.2 实验放号5.3 实验预定 六、免责说明 一、摘…

TryHackMe-Vulnerability Capstone练习

本文相关的TryHackMe实验房间链接&#xff1a;TryHackMe | Vulnerability Capstone 先nmap扫一下 接下来我们访问一下 接下来我们searchsploit找一下漏洞 searchsploit Fuel CMS 执行漏洞exp&#xff08;此处使用TryHackMe中的box&#xff09; 如果使用本地机需要下载exp&am…

孙思邈中文医疗大模型

孙思邈, 唐代医药学家、道士, 被后人尊称为"药王". 其十分重视民间的医疗经验, 不断积累走访, 及时记录下来, 写下著作《千金要方》. 唐朝建立后, 孙思邈接受朝廷的邀请, 与政府合作开展医学活动, 完成了世界上第一部国家药典《唐新本草》. 孙思邈中医药大模型(简称:…

手把手教你激活FL Studio 21.2.2.3914中文破解版2024年图文激活教程以及如何设置中文language

FL Studio 21.2.2.3914软件简介 fl studio 21.2.2.3914中文破解版作为一款极具创意性的音乐软件工作站软件&#xff0c;FL Studio已经成为了许多音乐制作人和音乐爱好者的首选。最新的FL Studio 21.2.2.3914中文破解版的发布&#xff0c;无疑将会引起更多人的关注。 ​ FL St…

力扣热门100题 - 4.寻找两个正序数组的中位数

力扣热门100题 - 4.寻找两个正序数组的中位数 题目描述&#xff1a;示例&#xff1a;提示&#xff1a;解题思路&#xff1a;代码&#xff1a; 题目链接&#xff1a;4.寻找两个正序数组的中位数 题目描述&#xff1a; 给定两个大小分别为 m 和 n 的正序&#xff08;从小到大&a…

微软Windows生态是怎么打造成功的?

&#xff08;1&#xff09;2015年Windows10&#xff1a;兼容性 我不得不再次佩服一下微软&#xff0c;Windows10是2015年出品的&#xff0c;但是仍然能正常运行绝大多数的Windows95软件&#xff0c;不用做任何的适配修改&#xff0c;连重新编译都不用&#xff0c;运行照样正常。…

Python调用matlab程序

matlab官网&#xff1a;https://ww2.mathworks.cn/?s_tidgn_logo matlab外部语言和库接口&#xff0c;包括 Python、Java、C、C、.NET 和 Web 服务。 matlab和python的版本 安装依赖配置 安装matlab的engine 找到matlab的安装目录&#xff1a;“xxx\ extern\engines\python…

华为WLAN无线配置实验

上面大概讲了配置的思路与原理&#xff0c;这里开始实际配置下。 一般建议采用旁挂AC&#xff0c;然后划分独立的设备管理网段&#xff0c;通过DHCP进行获取地址&#xff0c;其它的地址、接口、路由正常配置即可。 一、基本配置 拓扑图 AR1: # 配置接口地址和路由 interface Gi…

ElasticSearch-ElasticSearch实战-仿京东商城搜索(高亮)

注&#xff1a;此为笔者学习狂神说ElasticSearch的实战笔记&#xff0c;其中包含个人的笔记和理解&#xff0c;仅做学习笔记之用&#xff0c;更多详细资讯请出门左拐B站&#xff1a;狂神说!!! 七、ElasticSearch实战 仿京东商城搜索&#xff08;高亮&#xff09; 1、工程创建…

电脑插上u盘后看不到u盘?3个解决方法

随着U盘在我们日常生活和工作中的广泛应用&#xff0c;有时候插入U盘后却发现电脑无法正确识别&#xff0c;这对用户的数据传输和文件管理带来了困扰。本文将介绍电脑插上u盘后看不到u盘的常见原因&#xff0c;并提供三种有效的解决方法&#xff0c;以帮助用户迅速解决这一问题…

如何解锁屏幕破损的 iPhone

iPhone 15 是 Apple 最新、最出色的智能手机。它拥有时尚的设计、尖端的技术和众多功能&#xff0c;使其成为市场上最令人垂涎​​的设备之一。不幸的是&#xff0c;与所有智能手机一样&#xff0c;iPhone 14 容易发生可能导致屏幕破裂的事故和事故。破损的屏幕可能是毁灭性的&…

第二讲:数据结构 AcWing 826. 单链表

目录 数组模拟链表数组模拟单链表 单链表思路 && 代码 看图更好理解推荐一下y总的刷题网站 数组模拟链表 笔试的题目大部分 大部分涉及到链表都是十万级别的 用数组的方式创建链表速度很快&#xff0c;不会超时&#xff0c;而如果用new 一个结构体的话 大部分就是比较…

《Git 简易速速上手小册》第9章:Git 工作流程定制(2024 最新版)

文章目录 9.1 选择合适的工作流9.1.1 基础知识讲解9.1.2 重点案例&#xff1a;为中等规模的 Python 项目选择 Feature Branch 工作流9.1.3 拓展案例 1&#xff1a;适应 Gitflow 工作流的大型项目9.1.4 拓展案例 2&#xff1a;使用 Forking 工作流的开源 Python 项目 9.2 定制化…

【C++】【类和对象】拷贝构造函数

1.拷贝构造函数的特性&#xff1a; 1.拷贝构造函数用来构造一个与已存在对象一摸一样的对象 它只有单个形参&#xff0c;该形参是对本类类型对象的引用(一般常用const修饰)&#xff0c;在用已存在的类类型对象创建新对象时由编译器自动调用。 2.拷贝构造函数是构造函数的一种重…

nginx简单配置四种携带/时的拼接关系

一、代理静态文件 1、 当 location 尾部有 /&#xff0c;且代理地址尾部也有 / 时&#xff1a;&#xff08;常用&#xff09; location /test11/ {root /usr/local/nginx/html/; } 则访问 http://ip/test11/aaa&#xff0c;实际访问的是/usr/local/nginx/html/aaa2、 当…

Flask 入门7:使用 Flask-Moment 本地化日期和时间

如果Web应用的用户来自世界各地&#xff0c;那么处理日期和时间可不是一个简单的任务。服务器需要统一时间单位&#xff0c;这和用户所在的地理位置无关&#xff0c;所以一般使用协调世界时&#xff08;UTC&#xff09;。不过用户看到 UTC 格式的时间会感到困惑&#xff0c;他们…

数据库-MySQL 实战项目——房屋租赁管理系统数据库设计与实现(附源码)

一、前言 需求&#xff1a; 房屋租赁管理系统主要完成功能为&#xff1a; 房屋信息管理出租者信息管理求租者信息管理房屋出租信息管理系统管理&#xff08;员工信息管理、绩效管理等&#xff09; 备注&#xff1a; 1. 一个房屋有多个求租者。&#xff08;一对多&#xff0…

【10秒极速开服】幻兽帕鲁全自动部署服务器教程

幻兽帕鲁太火了&#xff0c;官方palworld服务器不稳定&#xff1f;不如自建服务器&#xff0c;基于腾讯云幻兽帕鲁服务器成本32元全自动部署幻兽帕鲁服务器&#xff0c;超简单有手就行&#xff0c;全程自动化一键部署10秒钟即可搞定&#xff0c;无需玩家手动部署幻兽帕鲁游戏程…

Agile Initiative, Epic, and Story/Task

Stories, also called “user stories,” are short requirements or requests written from the perspective of an end user. stories are something the team can commit to finish within a one- or two-week sprint.Epics are large bodies of work that can be broken do…