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 四、源程序及注释 …...
pam_env.so模块配置解析
在PAM(Pluggable Authentication Modules)配置中, /etc/pam.d/su 文件相关配置含义如下: 配置解析 auth required pam_env.so1. 字段分解 字段值说明模块类型auth认证类模块,负责验证用户身份&am…...
UR 协作机器人「三剑客」:精密轻量担当(UR7e)、全能协作主力(UR12e)、重型任务专家(UR15)
UR协作机器人正以其卓越性能在现代制造业自动化中扮演重要角色。UR7e、UR12e和UR15通过创新技术和精准设计满足了不同行业的多样化需求。其中,UR15以其速度、精度及人工智能准备能力成为自动化领域的重要突破。UR7e和UR12e则在负载规格和市场定位上不断优化…...
爬虫基础学习day2
# 爬虫设计领域 工商:企查查、天眼查短视频:抖音、快手、西瓜 ---> 飞瓜电商:京东、淘宝、聚美优品、亚马逊 ---> 分析店铺经营决策标题、排名航空:抓取所有航空公司价格 ---> 去哪儿自媒体:采集自媒体数据进…...
C++.OpenGL (14/64)多光源(Multiple Lights)
多光源(Multiple Lights) 多光源渲染技术概览 #mermaid-svg-3L5e5gGn76TNh7Lq {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-3L5e5gGn76TNh7Lq .error-icon{fill:#552222;}#mermaid-svg-3L5e5gGn76TNh7Lq .erro…...
云原生安全实战:API网关Kong的鉴权与限流详解
🔥「炎码工坊」技术弹药已装填! 点击关注 → 解锁工业级干货【工具实测|项目避坑|源码燃烧指南】 一、基础概念 1. API网关(API Gateway) API网关是微服务架构中的核心组件,负责统一管理所有API的流量入口。它像一座…...
Spring Security 认证流程——补充
一、认证流程概述 Spring Security 的认证流程基于 过滤器链(Filter Chain),核心组件包括 UsernamePasswordAuthenticationFilter、AuthenticationManager、UserDetailsService 等。整个流程可分为以下步骤: 用户提交登录请求拦…...
如何配置一个sql server使得其它用户可以通过excel odbc获取数据
要让其他用户通过 Excel 使用 ODBC 连接到 SQL Server 获取数据,你需要完成以下配置步骤: ✅ 一、在 SQL Server 端配置(服务器设置) 1. 启用 TCP/IP 协议 打开 “SQL Server 配置管理器”。导航到:SQL Server 网络配…...
面试高频问题
文章目录 🚀 消息队列核心技术揭秘:从入门到秒杀面试官1️⃣ Kafka为何能"吞云吐雾"?性能背后的秘密1.1 顺序写入与零拷贝:性能的双引擎1.2 分区并行:数据的"八车道高速公路"1.3 页缓存与批量处理…...
QT开发技术【ffmpeg + QAudioOutput】音乐播放器
一、 介绍 使用ffmpeg 4.2.2 在数字化浪潮席卷全球的当下,音视频内容犹如璀璨繁星,点亮了人们的生活与工作。从短视频平台上令人捧腹的搞笑视频,到在线课堂中知识渊博的专家授课,再到影视平台上扣人心弦的高清大片,音…...
webpack面试题
面试题:webpack介绍和简单使用 一、webpack(模块化打包工具)1. webpack是把项目当作一个整体,通过给定的一个主文件,webpack将从这个主文件开始找到你项目当中的所有依赖文件,使用loaders来处理它们&#x…...
