当前位置: 首页 > news >正文

WebSocket连接状态监控与自动重连实现

WebSocket连接状态监控与自动重连实现

下面我将实现一个具有连接状态监控和自动重连功能的WebSocket聊天室界面。

设计思路

  1. 创建直观的连接状态指示器
  2. 实现自动重连机制,包括:
    • 指数退避策略(重连间隔逐渐增加)
    • 最大重连次数限制
    • 手动重连按钮
  3. 添加心跳检测机制确保连接活跃
  4. 提供清晰的用户反馈

完整代码实现

<!DOCTYPE html>
<html lang="zh-CN">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>WebSocket聊天室 - 带自动重连</title><style>* {box-sizing: border-box;margin: 0;padding: 0;}body {font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;line-height: 1.6;color: #333;background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);min-height: 100vh;padding: 20px;display: flex;justify-content: center;align-items: center;}.container {width: 100%;max-width: 800px;background: white;border-radius: 12px;box-shadow: 0 10px 30px rgba(0, 0, 0, 0.15);overflow: hidden;}header {background: #4a6ee0;color: white;padding: 20px;text-align: center;position: relative;}h1 {font-size: 24px;margin-bottom: 5px;}.subtitle {font-size: 14px;opacity: 0.9;}.status-bar {display: flex;justify-content: space-between;align-items: center;padding: 12px 20px;background: #f0f4ff;border-bottom: 1px solid #e0e6ff;}.status {display: flex;align-items: center;gap: 10px;}.status-indicator {width: 12px;height: 12px;border-radius: 50%;}.status.connected .status-indicator {background: #4caf50;box-shadow: 0 0 8px #4caf50;}.status.connecting .status-indicator {background: #ff9800;animation: pulse 1.5s infinite;}.status.disconnected .status-indicator {background: #f44336;}.reconnect-info {font-size: 13px;color: #666;margin-left: 15px;}.chat-container {padding: 20px;height: 350px;overflow-y: auto;background: #fafbff;display: flex;flex-direction: column;}.message {margin-bottom: 15px;padding: 10px 15px;border-radius: 18px;max-width: 80%;word-break: break-word;position: relative;}.received {background: #e6eeff;border-top-left-radius: 4px;align-self: flex-start;}.sent {background: #4a6ee0;color: white;border-top-right-radius: 4px;margin-left: auto;}.system-message {align-self: center;background: #f0f4ff;color: #666;font-style: italic;text-align: center;max-width: 90%;font-size: 14px;}.message-input {display: flex;padding: 15px;border-top: 1px solid #e0e6ff;background: #fafbff;}input {flex: 1;padding: 12px 15px;border: 1px solid #d0d9ff;border-radius: 20px;outline: none;font-size: 16px;transition: border-color 0.3s;}input:focus {border-color: #4a6ee0;box-shadow: 0 0 0 2px rgba(74, 110, 224, 0.2);}button {background: #4a6ee0;color: white;border: none;border-radius: 20px;padding: 12px 20px;margin-left: 10px;cursor: pointer;font-weight: bold;transition: all 0.3s;}button:hover {background: #3a5ec0;transform: translateY(-2px);}button:active {transform: translateY(0);}button:disabled {background: #cccccc;cursor: not-allowed;transform: none;}.reconnect-button {background: #ff9800;}.reconnect-button:hover {background: #f57c00;}@keyframes pulse {0% { opacity: 1; }50% { opacity: 0.5; }100% { opacity: 1; }}.connection-stats {display: flex;padding: 10px 20px;background: #f8f9ff;border-top: 1px solid #e0e6ff;font-size: 13px;color: #666;justify-content: space-between;}</style>
</head>
<body><div class="container"><header><h1>WebSocket聊天室</h1><div class="subtitle">带自动重连和连接状态监控</div></header><div class="status-bar"><div class="status disconnected" id="status"><div class="status-indicator"></div><span id="statusText">连接已断开</span><span class="reconnect-info" id="reconnectInfo"></span></div><button id="connectButton" class="reconnect-button">连接</button></div><div class="chat-container" id="chatContainer"><div class="message system-message">欢迎使用WebSocket聊天室!点击"连接"按钮开始。</div></div><div class="message-input"><input type="text" id="messageInput" placeholder="输入消息..." disabled><button id="sendButton" disabled>发送</button></div><div class="connection-stats"><span id="connectionStats">连接次数: 0 | 消息数: 0</span><span id="latencyInfo">延迟: - ms</span></div></div><script>document.addEventListener('DOMContentLoaded', function() {const statusElement = document.getElementById('status');const statusText = document.getElementById('statusText');const reconnectInfo = document.getElementById('reconnectInfo');const connectButton = document.getElementById('connectButton');const chatContainer = document.getElementById('chatContainer');const messageInput = document.getElementById('messageInput');const sendButton = document.getElementById('sendButton');const connectionStats = document.getElementById('connectionStats');const latencyInfo = document.getElementById('latencyInfo');// WebSocket和状态变量let websocket = null;let reconnectAttempts = 0;const maxReconnectAttempts = 10;let reconnectTimer = null;let connectionCount = 0;let messageCount = 0;let heartbeatInterval = null;let lastHeartbeat = null;// 使用公共的WebSocket测试服务器const serverUrl = 'wss://echo.websocket.org';// 更新连接状态UIfunction updateConnectionStatus(state, message = '') {statusElement.className = 'status ' + state;switch(state) {case 'connected':statusText.textContent = '已连接';connectButton.textContent = '断开';connectButton.classList.remove('reconnect-button');messageInput.disabled = false;sendButton.disabled = false;reconnectInfo.textContent = '';break;case 'connecting':statusText.textContent = '连接中...';connectButton.textContent = '取消';connectButton.classList.add('reconnect-button');messageInput.disabled = true;sendButton.disabled = true;break;case 'disconnected':statusText.textContent = message || '连接已断开';connectButton.textContent = '重连';connectButton.classList.add('reconnect-button');messageInput.disabled = true;sendButton.disabled = true;break;}updateStats();}// 更新统计信息function updateStats() {connectionStats.textContent = `连接次数: ${connectionCount} | 消息数: ${messageCount}`;}// 添加消息到聊天窗口function addMessage(content, type = 'received') {const messageElement = document.createElement('div');messageElement.className = `message ${type}`;messageElement.textContent = content;chatContainer.appendChild(messageElement);// 滚动到底部chatContainer.scrollTop = chatContainer.scrollHeight;if (type === 'sent' || type === 'received') {messageCount++;updateStats();}}// 计算下一次重连的延迟(指数退避)function getReconnectDelay() {const baseDelay = 1000; // 1秒基础延迟const maxDelay = 30000; // 30秒最大延迟const delay = Math.min(maxDelay, baseDelay * Math.pow(1.5, reconnectAttempts));// 添加随机性避免所有客户端同时重连return delay + Math.random() * 1000;}// 建立WebSocket连接function connect() {// 清除现有的重连计时器if (reconnectTimer) {clearTimeout(reconnectTimer);reconnectTimer = null;}// 如果已有连接,先关闭if (websocket && websocket.readyState === WebSocket.OPEN) {disconnect();return;}updateConnectionStatus('connecting');try {websocket = new WebSocket(serverUrl);websocket.onopen = function(event) {connectionCount++;reconnectAttempts = 0;updateConnectionStatus('connected');addMessage('已成功连接到服务器', 'system-message');// 启动心跳检测startHeartbeat();};websocket.onmessage = function(event) {// 检查是否是心跳响应if (event.data === 'pong') {const now = new Date().getTime();const latency = now - lastHeartbeat;latencyInfo.textContent = `延迟: ${latency} ms`;return;}addMessage(event.data);};websocket.onclose = function(event) {// 清除心跳检测stopHeartbeat();addMessage(`连接关闭: ${event.code} ${event.reason || '无原因'}`, 'system-message');// 如果不是手动断开,尝试重连if (reconnectAttempts < maxReconnectAttempts) {reconnectAttempts++;const delay = getReconnectDelay();reconnectInfo.textContent = `尝试 ${reconnectAttempts}/${maxReconnectAttempts}, 下次尝试: ${Math.round(delay/1000)}`;reconnectTimer = setTimeout(connect, delay);updateConnectionStatus('disconnected', '连接断开,正在尝试重连...');} else {updateConnectionStatus('disconnected', '连接断开,已达最大重试次数');reconnectInfo.textContent = '';}};websocket.onerror = function(error) {addMessage('连接发生错误', 'system-message');console.error('WebSocket错误:', error);};} catch (error) {console.error('无法建立连接:', error);addMessage('无法连接到服务器: ' + error.message, 'system-message');updateConnectionStatus('disconnected');}}// 关闭WebSocket连接function disconnect() {// 清除重连计时器if (reconnectTimer) {clearTimeout(reconnectTimer);reconnectTimer = null;}// 清除心跳检测stopHeartbeat();if (websocket) {websocket.close();websocket = null;}updateConnectionStatus('disconnected', '连接已断开');reconnectAttempts = 0;reconnectInfo.textContent = '';}// 发送消息function sendMessage() {const message = messageInput.value.trim();if (message && websocket && websocket.readyState === WebSocket.OPEN) {websocket.send(message);addMessage(message, 'sent');messageInput.value = '';}}// 启动心跳检测function startHeartbeat() {// 每10秒发送一次心跳heartbeatInterval = setInterval(() => {if (websocket && websocket.readyState === WebSocket.OPEN) {lastHeartbeat = new Date().getTime();websocket.send('ping');}}, 10000);}// 停止心跳检测function stopHeartbeat() {if (heartbeatInterval) {clearInterval(heartbeatInterval);heartbeatInterval = null;}}// 连接/断开按钮点击事件connectButton.addEventListener('click', function() {if (websocket && websocket.readyState === WebSocket.OPEN) {disconnect();} else if (reconnectTimer) {// 取消重连clearTimeout(reconnectTimer);reconnectTimer = null;reconnectAttempts = maxReconnectAttempts; // 阻止自动重连updateConnectionStatus('disconnected', '连接已取消');reconnectInfo.textContent = '';} else {connect();}});// 发送按钮点击事件sendButton.addEventListener('click', sendMessage);// 按Enter键发送消息messageInput.addEventListener('keypress', function(event) {if (event.key === 'Enter') {sendMessage();}});// 初始状态updateConnectionStatus('disconnected');});</script>
</body>
</html>

功能说明

这个实现包含以下核心功能:

  1. 连接状态监控

    • 直观的视觉指示器(绿色=已连接,橙色=连接中,红色=已断开)
    • 详细的连接状态文本信息
  2. 自动重连机制

    • 使用指数退避算法,重试间隔逐渐增加
    • 最大重试次数限制(10次)
    • 显示下一次重连的剩余时间
  3. 心跳检测

    • 每10秒发送一次ping消息
    • 计算并显示网络延迟
  4. 连接统计

    • 显示连接次数和消息数量
    • 实时延迟显示
  5. 用户控制

    • 可以手动连接/断开
    • 可以取消自动重连过程

使用说明

  1. 页面加载后,点击"连接"按钮建立WebSocket连接
  2. 连接成功后,可以在输入框中输入消息并发送
  3. 如果连接断开,系统会自动尝试重连
  4. 可以随时点击"断开"按钮结束连接,或点击"重连"按钮手动重新连接

这个实现提供了健壮的WebSocket连接管理,适合在生产环境中使用。


文章转载自:

http://eMiYlyqi.LxbmL.cn
http://rSdKjETp.LxbmL.cn
http://7pPSkmgO.LxbmL.cn
http://CLEsbKYZ.LxbmL.cn
http://2B6LFoeE.LxbmL.cn
http://lYCgVqzx.LxbmL.cn
http://XclTsGHY.LxbmL.cn
http://jsGxhTXM.LxbmL.cn
http://NM8bNASf.LxbmL.cn
http://UWILrNoE.LxbmL.cn
http://z98iED0i.LxbmL.cn
http://Ip42o8P9.LxbmL.cn
http://e6gtpcKR.LxbmL.cn
http://6iag7RO1.LxbmL.cn
http://SHYhft3p.LxbmL.cn
http://TS1UTxbM.LxbmL.cn
http://3ExjWDiN.LxbmL.cn
http://pN0YKVXe.LxbmL.cn
http://C2LIVtaQ.LxbmL.cn
http://BXBOLMTi.LxbmL.cn
http://giRD8fP6.LxbmL.cn
http://6RzWL8S0.LxbmL.cn
http://MNBNzMjf.LxbmL.cn
http://jWN53FQi.LxbmL.cn
http://hmTcxfrt.LxbmL.cn
http://tjccDGIG.LxbmL.cn
http://87D6faEE.LxbmL.cn
http://Kvlfuoba.LxbmL.cn
http://2UIinVOT.LxbmL.cn
http://bXO5n5KT.LxbmL.cn
http://www.dtcms.com/a/380728.html

相关文章:

  • 目标计数论文阅读(1)Class-Agnostic Counting
  • LVGL移植2048小游戏全攻略
  • 大模型系列——ChatBI重构企业知识库
  • DEM(数字高程模型)详解
  • 软考 系统架构设计师系列知识点之杂项集萃(144)
  • R语言生物群落(生态)数据统计分析与绘图实践技术应用
  • DPO 深度解析:从公式到工程,从偏好数据到可复用训练管线
  • 今天继续学习Linux系统中shell脚本
  • 开源端到端训练多模态大模型LLaVA 深度拆解
  • 周志华《机器学习导论》第10章 降维与度量学习
  • PyQt置顶窗口
  • 基于图像和激光的多模态点云融合与视觉定位
  • 企业数据防护利器:Curtain e-locker 支持NCA合规
  • 【Vue2 ✨】Vue2 入门之旅 · 进阶篇(九):Vue2 性能优化
  • Java面试问题记录(二)
  • 势能分析 线段树 学习记录
  • 创维在线算号器-Skyworth创维密码计算器
  • 电商导购平台的搜索引擎优化:基于Elasticsearch的商品精准推荐系统
  • c++怎么读取文件里的内容和往文件里写入数据
  • C++实战:搜索引擎项目(二)
  • 【Vue2 ✨】Vue2 入门之旅 · 进阶篇(七):Vue Router 原理解析
  • Java 多线程(三)
  • 【tips】el-input-number 数字输入框初始值超出限制值后,v-model的问题
  • Red Hat Linux 全版本镜像下载
  • vm.nr_hugepages参数配置错误导致系统无法启动
  • 【Qt】Qt 设置全局字体
  • c++ cpp 多叉树简单处理文件重复包含问题
  • YOLO系列目标检测模型演进与YOLOv13深度解析
  • 【基础知识】仿函数与匿名函数对比
  • 澳鹏数据集月度精选 | 覆盖全模态理解、复杂推理、海量真题的快速部署方案