WebSocket实现消息实时推送
文章目录
- websocket介绍
- 特点
- 工作原理
- 用websocket实现实时推送
- 引入依赖
- WebSocket 函数定义
- 变量声明
- 初始化 WebSocket 连接
- WebSocket 连接的初始化和事件处理
- 连接打开事件
- 接收消息处理
- 连接关闭和重连机制
- 心跳机制
- 使用 WebSocket
- 代码完整显示
websocket介绍
WebSocket 是一种网络通信协议,旨在实现客户端和服务器之间的双向通信。它允许在单个 TCP 连接上进行全双工(即同时进行发送和接收)通信。WebSocket 特别适用于需要实时更新的应用,比如在线游戏、聊天应用、实时数据流等。
特点
双向通信:与传统的 HTTP 请求-响应模型不同,WebSocket 允许客户端和服务器同时发送和接收数据,这意味着一方可以主动向另一方发送消息,而不需要等待请求。
持久连接:WebSocket 建立的连接是持久的,客户端和服务器在一次连接后可以持续交换消息,而不需要频繁建立和关闭连接,从而减少了网络延迟和开销。
低延迟:由于使用了持久连接,WebSocket 可以减少消息传输中的延迟,使实时应用的响应速度更快。
轻量级:WebSocket 协议在数据传输中相对轻量,不需要像 HTTP 那样包含大量的头信息,数据包开销更小。
工作原理
握手:首先,客户端通过发送 HTTP 请求向服务器发起 WebSocket 连接。请求中包含一些特定的头信息,表明希望升级到 WebSocket 协议。
建立连接:服务器收到请求后,如果支持 WebSocket,将返回一个响应,确认升级连接。此时,HTTP 连接转变为 WebSocket 连接。
数据传输:连接建立后,双方可以自由地发送和接收消息。消息格式可以是文本(如 JSON)或二进制数据。
关闭连接:一方可以发送关闭帧,另一方收到后也会关闭连接,整个通信过程结束。
用websocket实现实时推送
这个封装提供了一个基础的 WebSocket 功能,可以支持实时消息推送。通过增加事件监听的管理、错误处理、灵活的心跳机制等功能,可以使这个封装更加健壮和灵活。
引入依赖
import { ElMessage, getCache } from "@/utils";
ElMessage: 用于显示消息提示。
getCache: 用于获取缓存数据,这里用来获取用户ID。
WebSocket 函数定义
function webSocket(params: string) {...return {onMessageFns,init,};
}
webSocket 函数接收一个参数 params(通常是用户ID),用于建立特定的 WebSocket 连接。
变量声明
let urlParams: string = params;const isReconnect = ref(true);let reconnection: any;let ws: WebSocket | null = null;let websocketConnectedCount = 0;let serverTimeoutObj: any = null;const hearbeatInterval = 300000; // 心跳间隔
is_reconnect: 用于标识是否可以重连。
ws: 存储 WebSocket 实例。
websocketConnectdCount : 记录连接失败次数。
serverTimeoutObj : 用于管理心跳检测的定时器。
初始化 WebSocket 连接
const init = () => {if (!("WebSocket" in window)) {ElMessage({message: "抱歉,浏览器不支持Websocket!",type: "warning",duration: 1000,});return;}try {initWebSocket();} catch (e) {console.log("尝试创建连接失败");reConnect();}
};
首先检查浏览器是否支持 WebSocket。如果支持,则尝试初始化连接;如果失败,则调用 reConnect 进行重连。
WebSocket 连接的初始化和事件处理
function initWebSocket() {const baseUrl = import.meta.env.VITE_BaseUrl?.slice(7);const url = `ws://${baseUrl}/websocket/${urlParams}`;ws = new WebSocket(url);ws.onopen = (e: Event) => {websocketOpen(e);};ws.onmessage = (e: MessageEvent) => {websocketOnMessage(e);};ws.onerror = () => {console.log("WebSocket连接发生错误");isReconnect.value = false;websocketConnectedCount++;if (websocketConnectedCount <= 5) {reConnect();}};ws.onclose = (e: CloseEvent) => {websocketClose(e);};}
创建 WebSocket 实例,并设置各类事件处理函数(打开、接收消息、错误、关闭)。
连接打开事件
function websocketOpen(e: Event) {console.log("连接成功");reset();start();const data = { sendType: "HEALTH" };ws?.send(JSON.stringify(data));}
}
连接成功时,重置心跳并发送健康检查消息。
接收消息处理
const onMessageFns = new Set<(e: MessageEvent) => void>();function websocketOnMessage(e: MessageEvent) {onMessageFns.forEach((callback) => callback(e));reset();start();return e.data;}
接收到消息时,执行所有注册的回调函数,并重置心跳。
连接关闭和重连机制
function websocketclose(e: any) {console.log(e);is_reconnect.value = false;console.log("connection closed (" + e.code + ")");
}let reConnect = () => {console.log("尝试重新连接");if (is_reconnect) return; // 如果已经连上就不再重连reconnection && clearTimeout(reconnection);reconnection = setTimeout(function () {init();}, 5000);
};
连接关闭时设置标识,并在指定时间后尝试重连。
心跳机制
const reset = () => {clearTimeout(serverTimeoutObj);};const start = () => {serverTimeoutObj = setInterval(() => {if (ws?.readyState === WebSocket.OPEN) {console.log("连接状态,发送消息保持连接");const data = { sendType: "HEALTH" };ws?.send(JSON.stringify(data));reset();} else {console.log("断开连接, 尝试重连");webSocket(urlParams);}}, hearbeatInterval);};
定期发送健康检查消息,保持连接活跃。
使用 WebSocket
import webSocket from "@/utils/websocket";const userId = getCache("userId");
const ws = webSocket(userId)!;onMounted(async () => {const addMessage = () => {ws.onMessageFns.add((value: MessageEvent) => {try {if (value.data !== "来自后台的反馈:连接成功" && value.data !== "SUCCESS") {const parsedData = JSON.parse(value.data);console.log("获取到的信息", parsedData);}} catch (error) {console.error("消息解析错误:", error);}});};addMessage();
});
在组件挂载时,获取用户ID并创建 WebSocket 实例。添加消息接收处理,过滤特定消息并处理 JSON 数据。
代码完整显示
import { ElMessage, getCache } from "@/utils";function webSocket(params: string) {let urlParams: string = params;const isReconnect = ref(true);let reconnection: any;let ws: WebSocket | null = null;let websocketConnectedCount = 0;let serverTimeoutObj: any = null;const hearbeatInterval = 300000; // 心跳间隔const init = () => {if (!("WebSocket" in window)) {ElMessage({message: "抱歉,浏览器不支持WebSocket!",type: "warning",duration: 1000,});return;}try {initWebSocket();} catch (e) {console.log("尝试创建连接失败");reConnect();}};function initWebSocket() {const baseUrl = import.meta.env.VITE_BaseUrl?.slice(7);const url = `ws://${baseUrl}/websocket/${urlParams}`;ws = new WebSocket(url);ws.onopen = (e: Event) => {websocketOpen(e);};ws.onmessage = (e: MessageEvent) => {websocketOnMessage(e);};ws.onerror = () => {console.log("WebSocket连接发生错误");isReconnect.value = false;websocketConnectedCount++;if (websocketConnectedCount <= 5) {reConnect();}};ws.onclose = (e: CloseEvent) => {websocketClose(e);};}function websocketOpen(e: Event) {console.log("连接成功");reset();start();const data = { sendType: "HEALTH" };ws?.send(JSON.stringify(data));}const onMessageFns = new Set<(e: MessageEvent) => void>();function websocketOnMessage(e: MessageEvent) {onMessageFns.forEach((callback) => callback(e));reset();start();return e.data;}function websocketClose(e: CloseEvent) {console.log("connection closed (" + e.code + ")");isReconnect.value = false;}const reConnect = () => {console.log("尝试重新连接");if (isReconnect.value) return; // 如果已经连上就不再重连reconnection && clearTimeout(reconnection);reconnection = setTimeout(init, 5000);};const reset = () => {clearTimeout(serverTimeoutObj);};const start = () => {serverTimeoutObj = setInterval(() => {if (ws?.readyState === WebSocket.OPEN) {console.log("连接状态,发送消息保持连接");const data = { sendType: "HEALTH" };ws?.send(JSON.stringify(data));reset();} else {console.log("断开连接, 尝试重连");webSocket(urlParams);}}, hearbeatInterval);};return {onMessageFns,init,};
}// 使用 WebSocket
import webSocket from "@/utils/websocket";const userId = getCache("userId");
const ws = webSocket(userId)!;onMounted(async () => {const addMessage = () => {ws.onMessageFns.add((value: MessageEvent) => {try {if (value.data !== "来自后台的反馈:连接成功" && value.data !== "SUCCESS") {const parsedData = JSON.parse(value.data);console.log("获取到的信息", parsedData);}} catch (error) {console.error("消息解析错误:", error);}});};addMessage();
});
相关文章:
WebSocket实现消息实时推送
文章目录 websocket介绍特点工作原理 用websocket实现实时推送引入依赖WebSocket 函数定义变量声明初始化 WebSocket 连接WebSocket 连接的初始化和事件处理连接打开事件接收消息处理连接关闭和重连机制心跳机制使用 WebSocket代码完整显示 websocket介绍 WebSocket 是一种网络…...
flink 内存配置(三):设置JobManager内存
flink 内存配置(一):设置Flink进程内存 flink 内存配置(二):设置TaskManager内存 flink 内存配置(三):设置JobManager内存 flink 内存配置(四)…...
蓝桥杯 Python组-神奇闹钟(datetime库)
神奇闹钟 传送门: 0神奇闹钟 - 蓝桥云课 问题描述 小蓝发现了一个神奇的闹钟,从纪元时间(1970 年 11 日 00:00:00)开始,每经过 x 分钟,这个闹钟便会触发一次闹铃 (…...
解决阿里云三个月证书过期 免费SSL证书部署教程
相信有上线过自己的网站、小程序经验的同学深有体会,给服务加上 SSL 证书还挺麻烦的,尤其是没有运维经验的同学。本来最省事的方法是买个证书,但是一看价格,还是算了吧,动辄就是几万块一年。作为个人来说,这…...
VBA03-变量
一、什么是变量 变量是一个自定义名称的储存单位,变量是一个载体。 二、代码调试 在代码逐句运行的过程中查看变量的存储内容。 2-1、示例1 2-2、示例 三、变量的数据类型 若是定义的数据类型的变量,存储了超出了她范围的数,则会报溢出。 注…...
docker-ce-stable‘ 下载元数据失败 : Cannot download repomd.xml: Cannot download
看起来你在尝试安装 containerd.io-1.6.32 时遇到了问题,因为 docker-ce-stable 仓库的元数据下载失败。以下是一些可能的解决方案: 1. 检查仓库配置 确保你的 /etc/yum.repos.d/ 目录下的 docker-ce.repo 文件配置正确。你可以尝试手动编辑该文件&…...
C中定义字符串有下列几种形式
字符串常量,char数组,char指针之间的差异 1、字符串常量: 位于一对双括号中的任何字符。双引号里的字符加上编译器自动提供的结束标志\0字符,作为一个字符串存储在内存中。 例如: printf("%s","hello"); /…...
写一个小日历
以下是一个示例,展示了如何创建一个基本的日历 日历 1. HTML 结构 首先,创建一个基本的 HTML 结构,用于展示日历。 <!DOCTYPE html> <html lang"zh"> <head><meta charset"UTF-8"><meta na…...
【数据库】elasticsearch
1、架构 es会为每个索引创建一定数量的主分片和副本分片。 分片(Shard): 将索引数据分割成多个部分,每个部分都是一个独立的索引。 主要目的是实现数据的分布式存储和并行处理,从而提高系统的扩展性和性能。 在创建索…...
Rust 构建 TCP/UDP 网络服务
第四章 异步编程与网络通信 第二节 构建 TCP/UDP 网络服务 在现代应用程序中,网络通信是核心功能之一。本节将重点介绍如何在 Rust 中构建基本的 TCP 和 UDP 网络服务,涵盖实际的代码示例、最佳实践以及最新的技术方案,以帮助开发者掌握网络…...
docker镜像文件导出导入
1. 导出容器(包含内部服务)为镜像文件(docker commit方法) 原理:docker commit命令允许你将一个容器的当前状态保存为一个新的镜像。这个新镜像将包含容器内所有的文件系统更改,包括安装的软件、配置文件等…...
ViT面试知识点
文章目录 VITCLIPBlipSAMLSegFast TransformerYOLO系列问题 BatchNorm是对一个batch-size样本内的每个特征做归一化,LayerNorm是对每个样本的所有特征做归一化。 Layer Normalization(层归一化,简称LayerNorm)是一种在深度学习中…...
ChatGPT 和 RAG(检索增强生成)的区别;ChatGPT 和 RAG 的联系
目录 ChatGPT 和 RAG(检索增强生成)的区别 知识来源与利用方式 回答准确性和可靠性 模型架构和复杂性 适用场景 ChatGPT 和 RAG 的联系 ChatGPT 和 RAG(检索增强生成)的区别 知识来源与利用方式 ChatGPT:是基于大规模预训练的语言模型,知识是在预训练过程中从大量的…...
qt获取本机IP和定位
前言: 在写一个天气预报模块时,需要一个定位功能,在网上翻来翻去才找着,放在这里留着回顾下,也帮下有需要的人 正文: 一开始我想着直接调用百度地图的API来定位, 然后我就想先获取本机IP的方…...
CodeQL学习笔记(5)-CodeQL for Java(AST、元数据、调用图)
最近在学习CodeQL,对于CodeQL就不介绍了,目前网上一搜一大把。本系列是学习CodeQL的个人学习笔记,根据个人知识库笔记修改整理而来的,分享出来共同学习。个人觉得QL的语法比较反人类,至少与目前主流的这些OOP语言相比&…...
服装品牌零售业态融合中的创新发展:以开源 AI 智能名片 S2B2C 商城小程序为视角
摘要:本文以服装品牌零售业态融合为背景,探讨信息流优化和资金流创新的重要作用,并结合开源 AI 智能名片 S2B2C 商城小程序,分析其如何进一步推动服装品牌在零售领域的发展,提高运营效率和用户体验,实现商业…...
前端将网页转换为pdf并支持下载与上传
1.pdf下载 handleExport() {const fixedH document.getElementById("fixed-h");const pageOne document.getElementById("mix-print-box-one");const pageTwo document.getElementById("mix-print-box-two");fixedH.style.height 30vh;pageO…...
Android 依赖统一配置管理(Version Catalogs)
最近升级了Android Studio版本到Koala Feature Drop | 2024.1.2,新建项目后发现项目配置又有变化,默认开始使用了一个名叫 Gradle 版本目录的东西,当然也可以称之为依赖统一配置管理,一开始还有点陌生,但是经过一番了解…...
如何为数据看板产品接入实时行情接口并展示行情
在金融科技领域,实时数据是分析和决策的关键因素。通过AllTick的实时行情API,您可以轻松将实时市场数据集成到数据看板产品中,为用户提供丰富的市场洞察。本文将详细介绍如何使用AllTick API,通过WebSocket协议接收并展示实时市场…...
数据结构 C/C++(实验一:线性表)
(大家好,今天分享的是数据结构的相关知识,大家可以在评论区进行互动答疑哦~加油!💕) 目录 提要:实验题目 一、实验目的 二、实验内容及要求 三、算法思想 实验1 实验2 四、源程序及注释 …...
水库调度员必看:动态规划在月度发电计划中的5个避坑指南
水库调度员实战指南:动态规划在月度发电计划中的5个关键避坑策略 在水利工程领域,水库调度是一项集科学性、技术性和艺术性于一体的复杂工作。作为水库调度员,我们每天都在与时间、水量和电力需求进行着精妙的博弈。而动态规划作为一种强大的…...
别再死记硬背了!用Python和SymPy库5分钟可视化理解泰勒公式的逼近过程
用Python动态可视化泰勒公式:5行代码理解多项式逼近本质 数学公式的抽象性常常成为学习者的障碍,尤其是泰勒公式这种涉及无限逼近概念的内容。传统的静态图示和理论推导虽然严谨,却难以直观展示"以直代曲"的动态过程。本文将用Pyth…...
WSABuilds GitHub Actions构建流程解析:自动化CI/CD管道配置
WSABuilds GitHub Actions构建流程解析:自动化CI/CD管道配置 【免费下载链接】WSABuilds Run Windows Subsystem For Android on your Windows 10 and Windows 11 PC using prebuilt binaries with Google Play Store (MindTheGapps) and/or Magisk or KernelSU (ro…...
文件夹色彩标记系统:Folcolor效能倍增指南
文件夹色彩标记系统:Folcolor效能倍增指南 【免费下载链接】Folcolor Windows explorer folder coloring utility 项目地址: https://gitcode.com/gh_mirrors/fo/Folcolor 在信息爆炸的数字化时代,Windows用户每天面对成百上千个黄色文件夹&#…...
uniapp定位踩坑记:腾讯地图误差1km?高德地图精准配置全攻略
Uniapp定位精度优化实战:从腾讯地图1km误差到高德厘米级精准配置 最近在开发一款外卖配送类应用时,我被定位精度问题折磨得够呛。原本以为接入腾讯地图SDK就能轻松搞定,结果实测发现定位偏差经常达到800米以上——这对于需要精确到楼栋的外卖…...
LeetCode 2946. 循环移位后的矩阵相似检查【数学周期性+原地比较】简单
本文属于「征服LeetCode」系列文章之一,这一系列正式开始于2021/08/12。由于LeetCode上部分题目有锁,本系列将至少持续到刷完所有无锁题之日为止;由于LeetCode还在不断地创建新题,本系列的终止日期可能是永远。在这一系列刷题文章…...
YimMenu安全增强指南:四阶法实现GTA V体验升级
YimMenu安全增强指南:四阶法实现GTA V体验升级 【免费下载链接】YimMenu YimMenu, a GTA V menu protecting against a wide ranges of the public crashes and improving the overall experience. 项目地址: https://gitcode.com/GitHub_Trending/yi/YimMenu …...
临近起飞,在哪个平台更容易捡漏特价机票?2026年实测指南
“机票越临近起飞越便宜”——这个说法你一定听过。每逢假期临近,总有人在社交媒体上分享自己“起飞前两小时抢到白菜价机票”的神奇经历。但当你真的想在清明、五一出行前“赌一把”时,往往发现价格不仅没降,反而翻倍了。那么问题来了&#…...
深度学习迁移学习:从原理到实践
深度学习迁移学习:从原理到实践 1. 背景与动机 深度学习模型在各种任务上取得了显著的性能提升,但这些模型通常需要大量的标注数据和计算资源进行训练。在实际应用中,我们经常面临以下挑战: 数据不足:某些任务的标注数…...
基于spring和vue的企业原材料库存盘点食品厂管理系统
目录技术选型与架构设计核心功能模块划分数据库设计要点关键技术实现前端交互优化系统安全措施测试与部署方案扩展性设计项目技术支持源码获取详细视频演示 :文章底部获取博主联系方式!同行可合作技术选型与架构设计 后端采用Spring Boot框架࿰…...
