简易的 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

相关文章

C++如何通过Qt反射机制实现数据类序列化

《C++如何通过Qt反射机制实现数据类序列化》在C++工程中经常需要使用数据类,并对数据类进行存储、打印、调试等操作,所以本文就来聊聊C++如何通过Qt反射机制实现数据类序列化吧... 目录设计预期设计思路代码实现使用方法在 C++ 工程中经常需要使用数据类,并对数据类进行存储、打印、调试等操作。由于数据类

SpringRetry重试机制之@Retryable注解与重试策略详解

《SpringRetry重试机制之@Retryable注解与重试策略详解》本文将详细介绍SpringRetry的重试机制,特别是@Retryable注解的使用及各种重试策略的配置,帮助开发者构建更加健... 目录引言一、SpringRetry基础知识二、启用SpringRetry三、@Retryable注解

SpringKafka错误处理(重试机制与死信队列)

《SpringKafka错误处理(重试机制与死信队列)》SpringKafka提供了全面的错误处理机制,通过灵活的重试策略和死信队列处理,下面就来介绍一下,具有一定的参考价值,感兴趣的可以了解一下... 目录引言一、Spring Kafka错误处理基础二、配置重试机制三、死信队列实现四、特定异常的处理策略五

关于WebSocket协议状态码解析

《关于WebSocket协议状态码解析》:本文主要介绍关于WebSocket协议状态码的使用方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录WebSocket协议状态码解析1. 引言2. WebSocket协议状态码概述3. WebSocket协议状态码详解3

java中反射(Reflection)机制举例详解

《java中反射(Reflection)机制举例详解》Java中的反射机制是指Java程序在运行期间可以获取到一个对象的全部信息,:本文主要介绍java中反射(Reflection)机制的相关资料... 目录一、什么是反射?二、反射的用途三、获取Class对象四、Class类型的对象使用场景1五、Class

Java springBoot初步使用websocket的代码示例

《JavaspringBoot初步使用websocket的代码示例》:本文主要介绍JavaspringBoot初步使用websocket的相关资料,WebSocket是一种实现实时双向通信的协... 目录一、什么是websocket二、依赖坐标地址1.springBoot父级依赖2.springBoot依赖

Python结合Flask框架构建一个简易的远程控制系统

《Python结合Flask框架构建一个简易的远程控制系统》这篇文章主要为大家详细介绍了如何使用Python与Flask框架构建一个简易的远程控制系统,能够远程执行操作命令(如关机、重启、锁屏等),还... 目录1.概述2.功能使用系统命令执行实时屏幕监控3. BUG修复过程1. Authorization

Nginx之upstream被动式重试机制的实现

《Nginx之upstream被动式重试机制的实现》本文主要介绍了Nginx之upstream被动式重试机制的实现,可以通过proxy_next_upstream来自定义配置,具有一定的参考价值,感兴... 目录默认错误选择定义错误指令配置proxy_next_upstreamproxy_next_upst

Spring排序机制之接口与注解的使用方法

《Spring排序机制之接口与注解的使用方法》本文介绍了Spring中多种排序机制,包括Ordered接口、PriorityOrdered接口、@Order注解和@Priority注解,提供了详细示例... 目录一、Spring 排序的需求场景二、Spring 中的排序机制1、Ordered 接口2、Pri

JavaWeb-WebSocket浏览器服务器双向通信方式

《JavaWeb-WebSocket浏览器服务器双向通信方式》文章介绍了WebSocket协议的工作原理和应用场景,包括与HTTP的对比,接着,详细介绍了如何在Java中使用WebSocket,包括配... 目录一、概述二、入门2.1 POM依赖2.2 编写配置类2.3 编写WebSocket服务2.4 浏