WebSocket协议详解:从核心原理到实战应用的全双工通信指南
在实时通信需求日益增长的今天传统HTTP请求-响应模式的局限性逐渐暴露特别是在需要服务器主动推送数据的场景中。WebSocket协议的出现彻底改变了这一局面为开发者提供了真正的全双工通信能力。本文将深入解析WebSocket技术的核心原理、实战应用及最佳实践帮助开发者从入门到精通掌握这一重要技术。1. WebSocket核心概念解析1.1 什么是WebSocket协议WebSocket是一种在单个TCP连接上进行全双工通信的协议于2011年被IETF标准化为RFC 6455。与传统的HTTP协议不同WebSocket允许服务器和客户端之间建立持久连接双方都可以随时主动发送数据而不需要像HTTP那样每次通信都要重新建立连接。从技术架构角度看WebSocket协议在建立连接时使用HTTP/HTTPS进行握手握手成功后协议升级为WebSocket协议此后通信双方使用WebSocket帧格式进行数据传输。这种设计既兼容现有的HTTP基础设施又提供了更高效的通信机制。1.2 WebSocket与HTTP长轮询的区别很多开发者容易将WebSocket与HTTP长轮询混淆实际上两者有本质区别。HTTP长轮询本质上还是基于请求-响应模式客户端发送请求后服务器保持连接直到有数据可返回或者超时。这种方式虽然能实现类似实时通信的效果但存在明显的性能瓶颈。相比之下WebSocket具有以下优势更低的延迟消息可以直接发送不需要建立新的HTTP请求更少的网络开销不需要重复的HTTP头部信息真正的双向通信服务器可以主动推送数据更好的连接管理单个连接可以持续复用1.3 WebSocket适用场景分析WebSocket特别适合以下类型的应用场景实时数据展示股票行情、实时监控系统、体育赛事比分等需要实时更新数据的应用。传统方案需要频繁轮询服务器而WebSocket可以在数据变化时立即推送到客户端。在线协作工具协同编辑文档、在线白板等需要多用户实时协作的场景。WebSocket能够确保所有用户的操作实时同步。即时通讯应用聊天应用、在线客服系统等。WebSocket的低延迟特性保证了消息的及时送达。游戏和交互应用多人在线游戏、虚拟现实应用等对实时性要求极高的场景。2. WebSocket协议技术细节2.1 握手过程详解WebSocket连接的建立始于一个特殊的HTTP请求即握手过程。客户端发送的握手请求包含以下关键头部GET /chat HTTP/1.1 Host: server.example.com Upgrade: websocket Connection: Upgrade Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ Sec-WebSocket-Version: 13其中Sec-WebSocket-Key是一个随机生成的16字节值的Base64编码服务器需要对此进行验证。服务器响应如下HTTP/1.1 101 Switching Protocols Upgrade: websocket Connection: Upgrade Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbKxOoSec-WebSocket-Accept的值是通过将客户端发送的Key与固定的GUID字符串258EAFA5-E914-47DA-95CA-C5AB0DC85B11拼接然后计算SHA-1哈希值最后进行Base64编码得到。2.2 数据帧格式WebSocket协议使用特定的帧格式传输数据。每个WebSocket帧包含以下部分0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 -------------------------------------------------------- |F|R|R|R| opcode|M| Payload len | Extended payload length | |I|S|S|S| (4) |A| (7) | (16/64) | |N|V|V|V| |S| | (if payload len126/127) | | |1|2|3| |K| | | ------------------------- - - - - - - - - - - - - - - - | Extended payload length continued, if payload len 127 | - - - - - - - - - - - - - - - ------------------------------- | |Masking-key, if MASK set to 1 | -------------------------------------------------------------- | Masking-key (continued) | Payload Data | -------------------------------- - - - - - - - - - - - - - - - : Payload Data continued ... : - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | Payload Data continued ... | ---------------------------------------------------------------关键字段说明FIN1位表示这是消息的最后一个片段RSV1-3各1位用于扩展协议Opcode4位定义帧类型文本、二进制、关闭等Mask1位指示负载数据是否被掩码Payload length7位、716位或764位表示负载数据长度2.3 协议控制帧WebSocket定义了多种控制帧用于管理连接关闭帧Close Frame用于优雅关闭连接可以包含关闭原因代码。// 关闭帧示例 WebSocket.CLOSED 3 WebSocket.CLOSING 2 WebSocket.OPEN 1 WebSocket.CONNECTING 0Ping/Pong帧用于保持连接活跃和检测连接状态。服务器可以发送Ping帧客户端必须回复Pong帧。3. 环境准备与开发工具3.1 浏览器兼容性检查现代浏览器对WebSocket的支持已经相当完善但在实际开发中仍需考虑兼容性问题。可以通过以下代码检测浏览器支持情况// 检测浏览器是否支持WebSocket if (window.WebSocket) { console.log(浏览器支持WebSocket); } else { console.log(浏览器不支持WebSocket需要降级方案); // 可以考虑使用Socket.IO等兼容方案 }主要浏览器的WebSocket支持情况Chrome4.0 完全支持Firefox6.0 完全支持Safari5.0 完全支持Edge12.0 完全支持Internet Explorer10.0 部分支持3.2 开发工具推荐WebSocket客户端测试工具WebSocket King功能强大的WebSocket测试客户端Postman新版本支持WebSocket测试浏览器开发者工具Chrome/Firefox内置WebSocket监控服务器端开发库Node.jsws、socket.io库JavaSpring WebSocket、Tomcat WebSocketPythonwebsockets、Django ChannelsGogorilla/websocket3.3 安全考虑在生产环境中使用WebSocket时安全是首要考虑因素WSS协议始终使用WebSocket Securewss://而不是ws://确保数据传输加密。// 正确的安全连接方式 const socket new WebSocket(wss://example.com/websocket); // 避免使用不安全的连接 // const socket new WebSocket(ws://example.com/websocket); // 不安全Origin验证服务器端应该验证请求的Origin头防止跨站WebSocket劫持。输入验证对所有接收到的WebSocket消息进行严格的验证和清理。4. WebSocket客户端开发实战4.1 基础客户端实现下面是一个完整的WebSocket客户端示例包含连接管理、消息发送和接收!DOCTYPE html html head titleWebSocket客户端示例/title /head body div input typetext idmessageInput placeholder输入消息 button onclicksendMessage()发送/button /div div idmessages styleheight: 300px; overflow-y: scroll; border: 1px solid #ccc;/div script class WebSocketClient { constructor(url) { this.url url; this.socket null; this.reconnectAttempts 0; this.maxReconnectAttempts 5; this.reconnectInterval 3000; this.connect(); } connect() { try { this.socket new WebSocket(this.url); this.socket.onopen (event) { console.log(WebSocket连接已建立); this.reconnectAttempts 0; this.addMessage(系统, 连接成功); }; this.socket.onmessage (event) { const data JSON.parse(event.data); this.addMessage(data.sender, data.message); }; this.socket.onclose (event) { console.log(WebSocket连接已关闭); this.addMessage(系统, 连接断开); this.handleReconnection(); }; this.socket.onerror (error) { console.error(WebSocket错误:, error); this.addMessage(系统, 连接错误); }; } catch (error) { console.error(创建WebSocket连接失败:, error); } } send(message) { if (this.socket this.socket.readyState WebSocket.OPEN) { this.socket.send(JSON.stringify({ type: message, content: message, timestamp: Date.now() })); return true; } else { console.warn(WebSocket未连接无法发送消息); return false; } } handleReconnection() { if (this.reconnectAttempts this.maxReconnectAttempts) { this.reconnectAttempts; console.log(尝试重新连接... (${this.reconnectAttempts}/${this.maxReconnectAttempts})); setTimeout(() { this.connect(); }, this.reconnectInterval); } else { console.error(达到最大重连次数停止重连); } } addMessage(sender, message) { const messagesDiv document.getElementById(messages); const messageElement document.createElement(div); messageElement.innerHTML strong${sender}:/strong ${message}; messagesDiv.appendChild(messageElement); messagesDiv.scrollTop messagesDiv.scrollHeight; } close() { if (this.socket) { this.socket.close(); } } } // 使用示例 const client new WebSocketClient(wss://echo.websocket.org); function sendMessage() { const input document.getElementById(messageInput); const message input.value.trim(); if (message) { if (client.send(message)) { input.value ; } } } // 处理页面卸载 window.addEventListener(beforeunload, () { client.close(); }); /script /body /html4.2 高级特性实现在实际项目中我们通常需要实现更复杂的功能如心跳检测、自动重连、消息队列等class AdvancedWebSocketClient { constructor(url, options {}) { this.url url; this.options { heartbeatInterval: 30000, maxReconnectAttempts: 5, reconnectDelay: 1000, ...options }; this.socket null; this.reconnectAttempts 0; this.heartbeatTimer null; this.messageQueue []; this.isConnected false; this.eventHandlers { open: [], message: [], close: [], error: [] }; this.connect(); } connect() { try { this.socket new WebSocket(this.url); this.setupEventHandlers(); } catch (error) { this.handleError(error); } } setupEventHandlers() { this.socket.onopen (event) { this.isConnected true; this.reconnectAttempts 0; this.startHeartbeat(); this.flushMessageQueue(); this.emit(open, event); }; this.socket.onmessage (event) { // 处理心跳响应 if (event.data pong) { return; } try { const data JSON.parse(event.data); this.emit(message, data); } catch (error) { console.error(消息解析错误:, error); } }; this.socket.onclose (event) { this.isConnected false; this.stopHeartbeat(); this.emit(close, event); if (!event.wasClean) { this.handleReconnection(); } }; this.socket.onerror (error) { this.handleError(error); }; } send(data, options {}) { const message { id: this.generateMessageId(), timestamp: Date.now(), data: data, ...options }; if (this.isConnected) { this.socket.send(JSON.stringify(message)); } else { // 将消息加入队列等待连接恢复后发送 this.messageQueue.push(message); } } flushMessageQueue() { while (this.messageQueue.length 0 this.isConnected) { const message this.messageQueue.shift(); this.socket.send(JSON.stringify(message)); } } startHeartbeat() { this.stopHeartbeat(); this.heartbeatTimer setInterval(() { if (this.isConnected) { this.socket.send(ping); } }, this.options.heartbeatInterval); } stopHeartbeat() { if (this.heartbeatTimer) { clearInterval(this.heartbeatTimer); this.heartbeatTimer null; } } handleReconnection() { if (this.reconnectAttempts this.options.maxReconnectAttempts) { this.reconnectAttempts; const delay this.options.reconnectDelay * Math.pow(2, this.reconnectAttempts - 1); console.log(等待 ${delay}ms 后尝试第 ${this.reconnectAttempts} 次重连); setTimeout(() { this.connect(); }, delay); } else { console.error(达到最大重连次数停止重连); } } on(event, handler) { if (this.eventHandlers[event]) { this.eventHandlers[event].push(handler); } } emit(event, data) { if (this.eventHandlers[event]) { this.eventHandlers[event].forEach(handler handler(data)); } } generateMessageId() { return Math.random().toString(36).substr(2, 9); } handleError(error) { console.error(WebSocket错误:, error); this.emit(error, error); } close() { this.stopHeartbeat(); if (this.socket) { this.socket.close(); } } } // 使用示例 const advancedClient new AdvancedWebSocketClient(wss://echo.websocket.org, { heartbeatInterval: 25000, maxReconnectAttempts: 10 }); advancedClient.on(open, (event) { console.log(高级客户端连接成功); }); advancedClient.on(message, (data) { console.log(收到消息:, data); }); advancedClient.on(close, (event) { console.log(连接关闭:, event); });5. WebSocket服务器端开发5.1 Node.js服务器实现使用Node.js和ws库可以快速构建WebSocket服务器const WebSocket require(ws); const http require(http); const url require(url); class WebSocketServer { constructor(port 8080) { this.port port; this.server http.createServer(); this.wss new WebSocket.Server({ server: this.server }); this.clients new Map(); this.setupWebSocketServer(); } setupWebSocketServer() { this.wss.on(connection, (ws, request) { const { query } url.parse(request.url, true); const clientId this.generateClientId(); // 存储客户端信息 this.clients.set(clientId, { ws: ws, id: clientId, userAgent: request.headers[user-agent], connectedAt: new Date() }); console.log(客户端 ${clientId} 已连接当前连接数: ${this.clients.size}); // 发送欢迎消息 this.sendToClient(clientId, { type: welcome, message: 连接成功, clientId: clientId, timestamp: new Date().toISOString() }); // 广播新用户上线通知排除自己 this.broadcast({ type: user_joined, clientId: clientId, timestamp: new Date().toISOString() }, clientId); // 处理消息 ws.on(message, (data) { try { const message JSON.parse(data); this.handleMessage(clientId, message); } catch (error) { console.error(消息解析错误:, error); this.sendToClient(clientId, { type: error, message: 消息格式错误 }); } }); // 处理连接关闭 ws.on(close, (code, reason) { this.clients.delete(clientId); console.log(客户端 ${clientId} 已断开原因: ${code} - ${reason}); // 广播用户下线通知 this.broadcast({ type: user_left, clientId: clientId, timestamp: new Date().toISOString() }); }); // 处理错误 ws.on(error, (error) { console.error(客户端 ${clientId} 错误:, error); }); }); // 启动心跳检测 this.startHeartbeat(); } handleMessage(clientId, message) { const client this.clients.get(clientId); if (!client) return; switch (message.type) { case chat: // 广播聊天消息 this.broadcast({ type: chat, from: clientId, content: message.content, timestamp: new Date().toISOString() }); break; case ping: // 响应心跳 this.sendToClient(clientId, { type: pong }); break; default: console.log(未知消息类型:, message.type); } } sendToClient(clientId, message) { const client this.clients.get(clientId); if (client client.ws.readyState WebSocket.OPEN) { client.ws.send(JSON.stringify(message)); } } broadcast(message, excludeClientId null) { this.clients.forEach((client, clientId) { if (clientId ! excludeClientId client.ws.readyState WebSocket.OPEN) { client.ws.send(JSON.stringify(message)); } }); } generateClientId() { return client_${Date.now()}_${Math.random().toString(36).substr(2, 9)}; } startHeartbeat() { setInterval(() { this.clients.forEach((client, clientId) { if (client.ws.readyState WebSocket.OPEN) { client.ws.ping(); } }); }, 30000); } start() { this.server.listen(this.port, () { console.log(WebSocket服务器运行在端口 ${this.port}); }); } getStats() { return { totalClients: this.clients.size, connectedClients: Array.from(this.clients.values()).filter( client client.ws.readyState WebSocket.OPEN ).length }; } } // 启动服务器 const server new WebSocketServer(8080); server.start(); // 优雅关闭处理 process.on(SIGINT, () { console.log(正在关闭服务器...); server.wss.close(() { console.log(WebSocket服务器已关闭); process.exit(0); }); });5.2 Spring Boot WebSocket实现对于Java技术栈Spring Boot提供了完善的WebSocket支持// WebSocket配置类 Configuration EnableWebSocket public class WebSocketConfig implements WebSocketConfigurer { Override public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) { registry.addHandler(new ChatWebSocketHandler(), /websocket) .setAllowedOrigins(*); } Bean public ServletServerContainerFactoryBean createWebSocketContainer() { ServletServerContainerFactoryBean container new ServletServerContainerFactoryBean(); container.setMaxTextMessageBufferSize(8192); container.setMaxBinaryMessageBufferSize(8192); return container; } } // WebSocket处理器 Component public class ChatWebSocketHandler extends TextWebSocketHandler { private static final MapString, WebSocketSession sessions new ConcurrentHashMap(); Override public void afterConnectionEstablished(WebSocketSession session) throws Exception { String sessionId session.getId(); sessions.put(sessionId, session); // 发送欢迎消息 MapString, Object welcomeMsg new HashMap(); welcomeMsg.put(type, welcome); welcomeMsg.put(message, 连接成功); welcomeMsg.put(sessionId, sessionId); welcomeMsg.put(timestamp, new Date()); session.sendMessage(new TextMessage(JSON.toJSONString(welcomeMsg))); // 广播用户上线通知 broadcastUserEvent(user_joined, sessionId); logger.info(客户端连接: sessionId , 当前连接数: sessions.size()); } Override protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception { String payload message.getPayload(); try { MapString, Object msgMap JSON.parseObject(payload, Map.class); String type (String) msgMap.get(type); String sessionId session.getId(); switch (type) { case chat: handleChatMessage(sessionId, msgMap); break; case ping: handlePing(sessionId); break; default: logger.warn(未知消息类型: type); } } catch (Exception e) { logger.error(消息处理错误, e); sendError(session, 消息格式错误); } } private void handleChatMessage(String sessionId, MapString, Object message) { MapString, Object chatMsg new HashMap(); chatMsg.put(type, chat); chatMsg.put(from, sessionId); chatMsg.put(content, message.get(content)); chatMsg.put(timestamp, new Date()); broadcast(chatMsg, sessionId); } private void handlePing(String sessionId) { WebSocketSession session sessions.get(sessionId); if (session ! null session.isOpen()) { MapString, Object pongMsg new HashMap(); pongMsg.put(type, pong); pongMsg.put(timestamp, new Date()); try { session.sendMessage(new TextMessage(JSON.toJSONString(pongMsg))); } catch (IOException e) { logger.error(发送pong消息失败, e); } } } private void broadcast(MapString, Object message, String excludeSessionId) { String jsonMessage JSON.toJSONString(message); sessions.forEach((sessionId, session) - { if (!sessionId.equals(excludeSessionId) session.isOpen()) { try { session.sendMessage(new TextMessage(jsonMessage)); } catch (IOException e) { logger.error(广播消息失败, e); } } }); } private void broadcastUserEvent(String eventType, String sessionId) { MapString, Object eventMsg new HashMap(); eventMsg.put(type, eventType); eventMsg.put(sessionId, sessionId); eventMsg.put(timestamp, new Date()); broadcast(eventMsg, sessionId); } private void sendError(WebSocketSession session, String errorMessage) { MapString, Object errorMsg new HashMap(); errorMsg.put(type, error); errorMsg.put(message, errorMessage); try { session.sendMessage(new TextMessage(JSON.toJSONString(errorMsg))); } catch (IOException e) { logger.error(发送错误消息失败, e); } } Override public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception { String sessionId session.getId(); sessions.remove(sessionId); // 广播用户下线通知 broadcastUserEvent(user_left, sessionId); logger.info(客户端断开: sessionId , 原因: status.getCode() - status.getReason()); } Override public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception { logger.error(WebSocket传输错误, exception); } }6. 性能优化与最佳实践6.1 连接管理优化连接池管理对于需要大量WebSocket连接的应用实现连接池可以有效管理资源。class WebSocketConnectionPool { constructor(maxConnections 100) { this.maxConnections maxConnections; this.connections new Map(); this.connectionQueue []; } createConnection(url, options {}) { return new Promise((resolve, reject) { if (this.connections.size this.maxConnections) { // 等待队列处理 this.connectionQueue.push({ url, options, resolve, reject }); return; } const connection new AdvancedWebSocketClient(url, options); const connectionId this.generateConnectionId(); connection.on(open, () { this.connections.set(connectionId, connection); resolve(connectionId); }); connection.on(close, () { this.connections.delete(connectionId); this.processQueue(); }); connection.on(error, (error) { this.connections.delete(connectionId); reject(error); this.processQueue(); }); }); } processQueue() { if (this.connectionQueue.length 0 this.connections.size this.maxConnections) { const { url, options, resolve, reject } this.connectionQueue.shift(); this.createConnection(url, options).then(resolve).catch(reject); } } getConnection(connectionId) { return this.connections.get(connectionId); } closeConnection(connectionId) { const connection this.connections.get(connectionId); if (connection) { connection.close(); this.connections.delete(connectionId); } } generateConnectionId() { return conn_${Date.now()}_${Math.random().toString(36).substr(2, 9)}; } getStats() { return { activeConnections: this.connections.size, queuedConnections: this.connectionQueue.length, maxConnections: this.maxConnections }; } }6.2 消息压缩与批处理对于传输大量数据的场景消息压缩和批处理可以显著提升性能class MessageOptimizer { constructor() { this.batchInterval 100; // 批处理间隔 this.batchTimer null; this.messageBuffer []; } // 消息压缩 compressMessage(message) { // 简单的JSON压缩实际项目中可以使用更高效的压缩算法 return JSON.stringify(message); } // 消息解压缩 decompressMessage(compressedMessage) { try { return JSON.parse(compressedMessage); } catch (error) { console.error(消息解压缩失败:, error); return null; } } // 添加消息到批处理队列 addToBatch(message, callback) { this.messageBuffer.push({ message, callback }); if (!this.batchTimer) { this.batchTimer setTimeout(() { this.processBatch(); }, this.batchInterval); } } // 处理批处理消息 processBatch() { if (this.messageBuffer.length 0) { this.batchTimer null; return; } const batch this.messageBuffer.splice(0, this.messageBuffer.length); this.batchTimer null; if (batch.length 1) { // 单条消息直接发送 const { message, callback } batch[0]; callback(this.compressMessage(message)); } else { // 多条消息合并发送 const batchMessage { type: batch, messages: batch.map(item item.message), timestamp: Date.now() }; // 执行所有回调 batch.forEach(({ callback }) { callback(this.compressMessage(batchMessage)); }); } } // 立即处理所有待处理消息 flush() { if (this.batchTimer) { clearTimeout(this.batchTimer); this.processBatch(); } } }6.3 监控与日志记录完善的监控系统对于生产环境至关重要class WebSocketMonitor { constructor() { this.metrics { connections: { total: 0, active: 0, failed: 0 }, messages: { sent: 0, received: 0, errors: 0 }, performance: { avgResponseTime: 0, maxResponseTime: 0 } }; this.startTime Date.now(); this.setupMetricsCollection(); } setupMetricsCollection() { // 定期收集和报告指标 setInterval(() { this.reportMetrics(); }, 60000); // 每分钟报告一次 } recordConnection(success true) { this.metrics.connections.total; if (success) { this.metrics.connections.active; } else { this.metrics.connections.failed; } } recordMessage(direction, success true) { if (direction sent) { this.metrics.messages.sent; } else if (direction received) { this.metrics.messages.received; } if (!success) { this.metrics.messages.errors; } } recordResponseTime(responseTime) { this.metrics.performance.avgResponseTime (this.metrics.performance.avgResponseTime * this.metrics.messages.received responseTime) / (this.metrics.messages.received 1); this.metrics.performance.maxResponseTime Math.max(this.metrics.performance.maxResponseTime, responseTime); } reportMetrics() { const uptime Date.now() - this.startTime; const report { ...this.metrics, uptime: this.formatUptime(uptime), timestamp: new Date().toISOString() }; console.log(WebSocket监控报告:, report); // 在实际项目中这里可以将报告发送到监控系统 // this.sendToMonitoringSystem(report); } formatUptime(ms) { const seconds Math.floor(ms / 1000); const minutes Math.floor(seconds / 60); const hours Math.floor(minutes / 60); return ${hours}h ${minutes % 60}m ${seconds % 60}s; } getMetrics() { return { ...this.metrics }; } } // 使用监控器 const monitor new WebSocketMonitor();7. 常见问题与解决方案7.1 连接稳定性问题问题1频繁断开重连解决方案实现指数退避重连机制class ReconnectionManager { constructor() { this.baseDelay 1000; this.maxDelay 30000; this.maxAttempts 10; this.currentAttempt 0; } async attemptReconnection(connectFunction) { if (this.currentAttempt this.maxAttempts) { throw new Error(达到最大重连次数); } const delay Math.min( this.baseDelay * Math.pow(2, this.currentAttempt), this.maxDelay ); this.currentAttempt; await new Promise(resolve setTimeout(resolve, delay)); try { await connectFunction(); this.currentAttempt 0; // 重置重连计数 return true; } catch (error) { console.error(第 ${this.currentAttempt} 次重连失败:, error); return false; } } reset() { this.currentAttempt 0; } }问题2防火墙和代理拦截解决方案使用WSS协议和合适的端口// 避免使用非常用端口 const secureWebSocket new WebSocket(wss://api.example.com:443/websocket); // 对于有严格防火墙的环境可以考虑WebSocket over HTTP/27.2 性能瓶颈问题问题大量连接时的内存泄漏解决方案实现连接生命周期管理class ConnectionManager { constructor() { this.connections new Map(); this.cleanupInterval setInterval(() { this.cleanupInactiveConnections(); }, 300000); // 每5分钟清理一次 } addConnection(connectionId, connection) { connection.lastActivity Date.now(); this.connections.set(connectionId, connection); } updateActivity(connectionId) { const connection this.connections.get(connectionId); if (connection) { connection.lastActivity Date.now(); } } cleanupInactiveConnections() { const now Date.now(); const maxInactiveTime 30 * 60 * 1000; // 30分钟 this.connections.forEach((connection, connectionId) { if (now - connection.lastActivity maxInactiveTime) { console.log(清理空闲连接: ${connectionId}); connection.close(); this.connections.delete(connectionId); } }); } closeAllConnections() { this.connections.forEach((connection) { connection.close(); }); this.connections.clear(); } }7.3 安全防护措施问题WebSocket安全漏洞解决方案综合安全防护策略class WebSocketSecurity { constructor() { this.rateLimiters new Map(); } // 速率限制 checkRateLimit(connectionId, messageType) { const key ${connectionId}_${messageType}

相关新闻