简易的 Websocket + 心跳机制 + 尝试重连

2024-08-23 21:04

本文主要是介绍简易的 Websocket + 心跳机制 + 尝试重连,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

文章目录

  • 演示
  • 大纲
  • 基础 WebSocket
  • 前端: 添加心跳机制
  • 前端: 尝试重新连接
  • 历史代码


还没有写完,bug 是有的,我在想解决办法了…

演示

请添加图片描述


大纲

  • 基础的 webSocket 连接
  • 前后端:添加心跳机制
  • 后端无心跳反应,前端尝试重新连接
  • 设置重新连接次数,超过最大尝试次数之后,不再尝试重新连接

基础 WebSocket

前端的基础就是这些,大概的效果是这样的

请添加图片描述

<body><button onclick="reConnect()">1. 重建连接</button><button onclick="sendMessage()">2. 发消息</button><button onclick="stopConnect()">3. 断开连接</button>
</body>
<script>let ws = null // 使用null来标记当前没有活动的 WebSocket 连接function createNewWebSocket() {if (ws && ws.readyState !== WebSocket.CLOSED) {ws.close() // 确保关闭旧的连接}ws = new WebSocket('ws://localhost:8080')ws.onopen = function (evt) {console.log('Connection open ...')}ws.onmessage = function (evt) {console.log('Received Message: ' + evt.data)}ws.onclose = function (evt) {console.log('Connection closed.')}}function sendMessage() {if (ws) ws.send(`前端发送:>> ${new Date()}`)}function stopConnect() {if (ws) ws.close()}function reConnect() {createNewWebSocket()}
</script>

后端的代码基本不变,所以我直接把心跳也做好
后端的心跳就是:拿到前端的值,如果是 ping 的话,就返回一个 pong,其他逻辑保持不变

const http = require('http')
const WebSocket = require('ws')
const server = http.createServer()
const wss = new WebSocket.Server({ server })wss.on('connection', (socket) => {console.log('webSocket 连接成功')socket.on('message', (message) => {// 将 Buffer 转换为字符串const messageStr = message.toString()const currentRandom = Math.random()const isSendPong = currentRandom < 0.5console.log('后端收到消息:>>' + messageStr)// 检查是否为心跳请求if (messageStr === 'ping') {socket.send(`当前随机值为 ${currentRandom}, 是否发送心跳:${isSendPong}`)//  50%的概率发送 "pong"if (isSendPong) {socket.send('pong') // 心跳响应}} else {const message = `后端发送消息:>> 你好前端~ ${new Date().toLocaleString()}`socket.send(message)}})socket.on('close', () => {console.log('websocket 已经关闭')})
})server.on('request', (request, response) => {response.writeHead(200, { 'Content-Type': 'text/plain' })response.end('Hello, World')
})server.listen(8080, () => {console.log('服务器已启动,端口号为 8080')
})

前端: 添加心跳机制

思路:前端写一个定时器,用于隔一段时间发送一个 ping
效果如下图所示请添加图片描述

好吧,false 的概率有点高,不顾可以看历史记录

我在后端设置了随机逻辑,模拟一下出错的场景,百分之50的概率回应前端的心跳,如果 true 的话,后端就回应前端的心跳,返回 pong

前端 代码如下

<body><button onclick="reConnect()">1. 重建连接</button><button onclick="sendMessage()">2. 发消息</button><button onclick="stopConnect()">3. 断开连接</button>
</body>
<script>let ws = null // 使用null来标记当前没有活动的 WebSocket 连接let heartbeatTimer = null // 心跳定时器const HEARTBEAT_INTERVAL = 5000 // 每隔 5 秒发送一次心跳function createNewWebSocket() {if (ws && ws.readyState !== WebSocket.CLOSED) {ws.close() // 确保关闭旧的连接}ws = new WebSocket('ws://localhost:8080')ws.onopen = function (evt) {console.log('Connection open ...')startHeartbeat()}ws.onmessage = function (evt) {console.log('Received Message: ' + evt.data)handleHeartbeatResponse(evt.data)}ws.onclose = function (evt) {console.log('Connection closed.')stopHeartbeat()}}function sendMessage() {if (ws) ws.send(`前端发送:>> ${new Date().toLocaleString()}`)}function stopConnect() {if (ws) ws.close()stopHeartbeat()}function reConnect() {createNewWebSocket()}function startHeartbeat() {heartbeatTimer = setInterval(() => {ws.send('ping')}, HEARTBEAT_INTERVAL)}function stopHeartbeat() {clearInterval(heartbeatTimer)heartbeatTimer = null}function handleHeartbeatResponse(message) {if (message === 'heartbeat') {console.log('Heartbeat received.')clearTimeout(heartbeatTimer) // 清除超时定时器startHeartbeat() // 重新启动心跳}}
</script>

前端: 尝试重新连接

设置一个场景: 前端发送三个心跳包,如果都没有反应,那么就判断为断开连接了,就去重新连接

历史代码

前端

<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8" /><meta name="viewport" content="width=device-width, initial-scale=1.0" /><title>Document</title></head><body><button id="btn">发消息</button><button id="stop">断链</button><button id="reconnect">重新连接</button></body><script>const btn = document.querySelector('#btn')const stop = document.querySelector('#stop')const reconnect = document.querySelector('#reconnect')let ws = null // 使用null来标记当前没有活动的WebSocket连接let heartbeatInterval = null // 存储心跳定时器let timeoutId = null // 存储超时定时器let reconnectAttempts = 0 // 重连尝试次数const maxReconnectAttempts = 3 // 最大重连次数function createNewWebSocket() {if (ws && ws.readyState !== WebSocket.CLOSED) {ws.close() // 确保关闭旧的连接}ws = new WebSocket('ws://localhost:8080')ws.onopen = function (evt) {console.log('Connection open ...')startHeartbeat() // 开始发送心跳}ws.onmessage = function (evt) {console.log('Received Message: ' + evt.data)// 检查是否为心跳响应if (evt.data === 'pong') {clearTimeout(timeoutId) // 清除超时定时器resetHeartbeatTimer() // 重置心跳定时器}}ws.onclose = function (evt) {console.log('Connection closed.')clearInterval(heartbeatInterval) // 清除心跳定时器reconnectWebSocket() // 尝试重新连接}}// 发送心跳包function sendHeartbeat() {if (ws) {ws.send('ping')timeoutId = setTimeout(() => {// 如果在超时时间内没有收到 "pong" 响应,则关闭当前连接console.log('超时,关闭连接')ws.close()}, 15000) // 设置超时时间为 15 秒}}// 启动心跳function startHeartbeat() {sendHeartbeat() // 立即发送第一个心跳包heartbeatInterval = setInterval(sendHeartbeat, 30000) // 每30秒发送一次}// 重置心跳定时器function resetHeartbeatTimer() {clearInterval(heartbeatInterval)heartbeatInterval = setInterval(sendHeartbeat, 30000) // 重新设置定时器}// 重新连接function reconnectWebSocket() {console.log('尝试重新连接', reconnectAttempts)// 检查是否超过最大重连次数if (reconnectAttempts < maxReconnectAttempts) {reconnectAttempts++createNewWebSocket()} else {console.log('超过最大重连次数,不再尝试连接')}}btn.addEventListener('click', () => {if (ws) {ws.send(`前端发送:>> ${new Date()}`)}})stop.addEventListener('click', () => {if (ws) {ws.close()}})reconnect.addEventListener('click', () => {createNewWebSocket()})</script>
</html>

后端

const http = require('http')
const WebSocket = require('ws')
const server = http.createServer()
const wss = new WebSocket.Server({ server })wss.on('connection', (socket) => {console.log('webSocket 连接成功')socket.on('message', (message) => {// 将 Buffer 转换为字符串const messageStr = message.toString();console.log('后端收到消息:>>' + messageStr);// 检查是否为心跳请求if (messageStr === 'ping') {socket.send('pong'); // 心跳响应} else {socket.send('后端发送消息:>> hello 我是 socket.send');}})socket.on('close', () => {console.log('websocket 已经关闭');})
})server.on('request', (request, response) => {response.writeHead(200, { 'Content-Type': 'text/plain' });response.end('Hello, World');
})server.listen(8080, () => {console.log('服务器已启动,端口号为 8080');
})

这篇关于简易的 Websocket + 心跳机制 + 尝试重连的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1100486

相关文章

Redis客户端连接机制的实现方案

《Redis客户端连接机制的实现方案》本文主要介绍了Redis客户端连接机制的实现方案,包括事件驱动模型、非阻塞I/O处理、连接池应用及配置优化,具有一定的参考价值,感兴趣的可以了解一下... 目录1. Redis连接模型概述2. 连接建立过程详解2.1 连php接初始化流程2.2 关键配置参数3. 最大连

深入浅出SpringBoot WebSocket构建实时应用全面指南

《深入浅出SpringBootWebSocket构建实时应用全面指南》WebSocket是一种在单个TCP连接上进行全双工通信的协议,这篇文章主要为大家详细介绍了SpringBoot如何集成WebS... 目录前言为什么需要 WebSocketWebSocket 是什么Spring Boot 如何简化 We

Spring Security 单点登录与自动登录机制的实现原理

《SpringSecurity单点登录与自动登录机制的实现原理》本文探讨SpringSecurity实现单点登录(SSO)与自动登录机制,涵盖JWT跨系统认证、RememberMe持久化Token... 目录一、核心概念解析1.1 单点登录(SSO)1.2 自动登录(Remember Me)二、代码分析三、

Go语言并发之通知退出机制的实现

《Go语言并发之通知退出机制的实现》本文主要介绍了Go语言并发之通知退出机制的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧... 目录1、通知退出机制1.1 进程/main函数退出1.2 通过channel退出1.3 通过cont

Spring Boot 中的默认异常处理机制及执行流程

《SpringBoot中的默认异常处理机制及执行流程》SpringBoot内置BasicErrorController,自动处理异常并生成HTML/JSON响应,支持自定义错误路径、配置及扩展,如... 目录Spring Boot 异常处理机制详解默认错误页面功能自动异常转换机制错误属性配置选项默认错误处理

Java中的xxl-job调度器线程池工作机制

《Java中的xxl-job调度器线程池工作机制》xxl-job通过快慢线程池分离短时与长时任务,动态降级超时任务至慢池,结合异步触发和资源隔离机制,提升高频调度的性能与稳定性,支撑高并发场景下的可靠... 目录⚙️ 一、调度器线程池的核心设计 二、线程池的工作流程 三、线程池配置参数与优化 四、总结:线程

基于Python实现简易视频剪辑工具

《基于Python实现简易视频剪辑工具》这篇文章主要为大家详细介绍了如何用Python打造一个功能完备的简易视频剪辑工具,包括视频文件导入与格式转换,基础剪辑操作,音频处理等功能,感兴趣的小伙伴可以了... 目录一、技术选型与环境搭建二、核心功能模块实现1. 视频基础操作2. 音频处理3. 特效与转场三、高

Android ClassLoader加载机制详解

《AndroidClassLoader加载机制详解》Android的ClassLoader负责加载.dex文件,基于双亲委派模型,支持热修复和插件化,需注意类冲突、内存泄漏和兼容性问题,本文给大家介... 目录一、ClassLoader概述1.1 类加载的基本概念1.2 android与Java Class

Spring Boot中WebSocket常用使用方法详解

《SpringBoot中WebSocket常用使用方法详解》本文从WebSocket的基础概念出发,详细介绍了SpringBoot集成WebSocket的步骤,并重点讲解了常用的使用方法,包括简单消... 目录一、WebSocket基础概念1.1 什么是WebSocket1.2 WebSocket与HTTP

Spring事务传播机制最佳实践

《Spring事务传播机制最佳实践》Spring的事务传播机制为我们提供了优雅的解决方案,本文将带您深入理解这一机制,掌握不同场景下的最佳实践,感兴趣的朋友一起看看吧... 目录1. 什么是事务传播行为2. Spring支持的七种事务传播行为2.1 REQUIRED(默认)2.2 SUPPORTS2