我将介绍WebSocket的服务端和客户端实现:

  1. 服务端实现 (Node.js + WS)
// server.js
const WebSocket = require('ws');
const http = require('http');

// 创建HTTP服务器
const server = http.createServer();
// 创建WebSocket服务器
const wss = new WebSocket.Server({ server });

// 存储所有连接的客户端
const clients = new Map();

// 处理连接
wss.on('connection', (ws, req) => {
  const clientId = Date.now();
  const clientInfo = {
    id: clientId,
    ws: ws,
    lastHeartbeat: Date.now()
  };
  
  // 存储客户端连接
  clients.set(clientId, clientInfo);
  
  console.log(`Client ${clientId} connected`);

  // 发送欢迎消息
  ws.send(JSON.stringify({
    type: 'welcome',
    message: `Welcome client ${clientId}`,
    clientId: clientId
  }));

  // 处理消息
  ws.on('message', (message) => {
    try {
      const data = JSON.parse(message);
      
      // 处理心跳
      if (data.type === 'heartbeat') {
        clientInfo.lastHeartbeat = Date.now();
        ws.send(JSON.stringify({ type: 'heartbeat', message: 'pong' }));
        return;
      }

      // 处理其他消息类型
      switch (data.type) {
        case 'broadcast':
          broadcast(data.message, clientId);
          break;
        case 'private':
          sendPrivateMessage(data.targetId, data.message, clientId);
          break;
        default:
          console.log(`Received message from client ${clientId}:`, data);
      }
    } catch (error) {
      console.error('Error processing message:', error);
    }
  });

  // 处理关闭连接
  ws.on('close', () => {
    console.log(`Client ${clientId} disconnected`);
    clients.delete(clientId);
    broadcast({
      type: 'system',
      message: `Client ${clientId} left`
    });
  });

  // 处理错误
  ws.on('error', (error) => {
    console.error(`Client ${clientId} error:`, error);
    clients.delete(clientId);
  });
});

// 广播消息给所有客户端
function broadcast(message, senderId) {
  clients.forEach((client, id) => {
    if (id !== senderId && client.ws.readyState === WebSocket.OPEN) {
      client.ws.send(JSON.stringify({
        type: 'broadcast',
        senderId: senderId,
        message: message
      }));
    }
  });
}

// 发送私聊消息
function sendPrivateMessage(targetId, message, senderId) {
  const targetClient = clients.get(parseInt(targetId));
  if (targetClient && targetClient.ws.readyState === WebSocket.OPEN) {
    targetClient.ws.send(JSON.stringify({
      type: 'private',
      senderId: senderId,
      message: message
    }));
  }
}

// 清理断开的连接
setInterval(() => {
  const now = Date.now();
  clients.forEach((client, id) => {
    if (now - client.lastHeartbeat > 30000) { // 30秒超时
      console.log(`Client ${id} timed out`);
      client.ws.terminate();
      clients.delete(id);
    }
  });
}, 10000);

// 启动服务器
const PORT = process.env.PORT || 8080;
server.listen(PORT, () => {
  console.log(`WebSocket server is running on port ${PORT}`);
});
  1. 前端实现
// websocket-client.js
class WebSocketClient {
  constructor(url) {
    this.url = url;
    this.ws = null;
    this.reconnectAttempts = 0;
    this.maxReconnectAttempts = 5;
    this.reconnectInterval = 3000;
    this.heartbeatInterval = null;
    this.listeners = new Map();
    this.clientId = null;
  }

  // 连接
  connect() {
    try {
      this.ws = new WebSocket(this.url);
      this.attachEventListeners();
    } catch (error) {
      console.error('WebSocket connection error:', error);
      this.handleReconnect();
    }
  }

  // 添加事件监听器
  attachEventListeners() {
    this.ws.onopen = () => {
      console.log('WebSocket connected');
      this.reconnectAttempts = 0;
      this.startHeartbeat();
      this.emit('connect');
    };

    this.ws.onmessage = (event) => {
      try {
        const data = JSON.parse(event.data);
        
        // 处理欢迎消息
        if (data.type === 'welcome') {
          this.clientId = data.clientId;
        }
        
        // 触发消息事件
        this.emit('message', data);
        
        // 处理特定类型的消息
        if (this.listeners.has(data.type)) {
          this.listeners.get(data.type).forEach(callback => callback(data));
        }
      } catch (error) {
        console.error('Error parsing message:', error);
      }
    };

    this.ws.onclose = () => {
      console.log('WebSocket disconnected');
      this.stopHeartbeat();
      this.emit('disconnect');
      this.handleReconnect();
    };

    this.ws.onerror = (error) => {
      console.error('WebSocket error:', error);
      this.emit('error', error);
    };
  }

  // 重连机制
  handleReconnect() {
    if (this.reconnectAttempts < this.maxReconnectAttempts) {
      this.reconnectAttempts++;
      console.log(`Reconnecting... Attempt ${this.reconnectAttempts}`);
      setTimeout(() => this.connect(), this.reconnectInterval);
    } else {
      console.error('Max reconnection attempts reached');
      this.emit('reconnectFailed');
    }
  }

  // 心跳机制
  startHeartbeat() {
    this.heartbeatInterval = setInterval(() => {
      if (this.ws.readyState === WebSocket.OPEN) {
        this.send({ type: 'heartbeat', message: 'ping' });
      }
    }, 15000); // 每15秒发送一次心跳
  }

  stopHeartbeat() {
    if (this.heartbeatInterval) {
      clearInterval(this.heartbeatInterval);
      this.heartbeatInterval = null;
    }
  }

  // 发送消息
  send(data) {
    if (this.ws && this.ws.readyState === WebSocket.OPEN) {
      this.ws.send(JSON.stringify(data));
    } else {
      console.error('WebSocket is not connected');
    }
  }

  // 发送广播消息
  broadcast(message) {
    this.send({
      type: 'broadcast',
      message: message
    });
  }

  // 发送私聊消息
  sendPrivateMessage(targetId, message) {
    this.send({
      type: 'private',
      targetId: targetId,
      message: message
    });
  }

  // 监听特定类型的消息
  on(type, callback) {
    if (!this.listeners.has(type)) {
      this.listeners.set(type, new Set());
    }
    this.listeners.get(type).add(callback);
  }

  // 移除监听器
  off(type, callback) {
    if (this.listeners.has(type)) {
      this.listeners.get(type).delete(callback);
    }
  }

  // 触发事件
  emit(type, data) {
    if (this.listeners.has(type)) {
      this.listeners.get(type).forEach(callback => callback(data));
    }
  }

  // 关闭连接
  close() {
    if (this.ws) {
      this.ws.close();
    }
    this.stopHeartbeat();
  }

  // 获取连接状态
  getState() {
    return this.ws ? this.ws.readyState : WebSocket.CLOSED;
  }

  // 获取客户端ID
  getClientId() {
    return this.clientId;
  }
}

// 使用示例
const ws = new WebSocketClient('ws://localhost:8080');

// 连接成功监听
ws.on('connect', () => {
  console.log('Connected to server');
});

// 接收消息监听
ws.on('message', (data) => {
  console.log('Received message:', data);
});

// 监听广播消息
ws.on('broadcast', (data) => {
  console.log('Broadcast message:', data);
});

// 监听私聊消息
ws.on('private', (data) => {
  console.log('Private message:', data);
});

// 连接断开监听
ws.on('disconnect', () => {
  console.log('Disconnected from server');
});

// 错误监听
ws.on('error', (error) => {
  console.error('WebSocket error:', error);
});

// 建立连接
ws.connect();

// 发送消息示例
ws.broadcast('Hello everyone!');
ws.sendPrivateMessage(123, 'Hello user 123!');

// 关闭连接
// ws.close();
  1. 聊天室示例
<!DOCTYPE html>
<html>
<head>
    <title>WebSocket Chat</title>
    <style>
        .chat-container {
            max-width: 600px;
            margin: 0 auto;
            padding: 20px;
        }
        .messages {
            height: 400px;
            overflow-y: auto;
            border: 1px solid #ccc;
            padding: 10px;
            margin-bottom: 10px;
        }
        .message {
            margin-bottom: 10px;
            padding: 5px;
        }
        .message.system { color: #666; }
        .message.broadcast { color: #333; }
        .message.private { color: #0066cc; }
        .input-container {
            display: flex;
            gap: 10px;
        }
        input[type="text"] {
            flex: 1;
            padding: 5px;
        }
        button {
            padding: 5px 10px;
        }
    </style>
</head>
<body>
    <div class="chat-container">
        <div class="messages" id="messages"></div>
        <div class="input-container">
            <input type="text" id="messageInput" placeholder="Type your message...">
            <input type="text" id="targetInput" placeholder="Target ID (for private message)">
            <button onclick="sendMessage()">Send</button>
            <button onclick="sendPrivate()">Send Private</button>
        </div>
    </div>

    <script>
        const ws = new WebSocketClient('ws://localhost:8080');
        const messagesDiv = document.getElementById('messages');
        const messageInput = document.getElementById('messageInput');
        const targetInput = document.getElementById('targetInput');

        function addMessage(message, type = 'broadcast') {
            const messageElement = document.createElement('div');
            messageElement.classList.add('message', type);
            messageElement.textContent = message;
            messagesDiv.appendChild(messageElement);
            messagesDiv.scrollTop = messagesDiv.scrollHeight;
        }

        ws.on('connect', () => {
            addMessage('Connected to chat server', 'system');
        });

        ws.on('message', (data) => {
            if (data.type === 'welcome') {
                addMessage(`Your client ID is: ${data.clientId}`, 'system');
            }
        });

        ws.on('broadcast', (data) => {
            addMessage(`${data.senderId}: ${data.message}`, 'broadcast');
        });

        ws.on('private', (data) => {
            addMessage(`Private from ${data.senderId}: ${data.message}`, 'private');
        });

        ws.on('disconnect', () => {
            addMessage('Disconnected from server', 'system');
        });

        function sendMessage() {
            const message = messageInput.value.trim();
            if (message) {
                ws.broadcast(message);
                addMessage(`You: ${message}`, 'broadcast');
                messageInput.value = '';
            }
        }

        function sendPrivate() {
            const message = messageInput.value.trim();
            const targetId = targetInput.value.trim();
            if (message && targetId) {
                ws.sendPrivateMessage(targetId, message);
                addMessage(`You to ${targetId}: ${message}`, 'private');
                messageInput.value = '';
            }
        }

        messageInput.addEventListener('keypress', (e) => {
            if (e.key === 'Enter') {
                sendMessage();
            }
        });

        ws.connect();
    </script>
</body>
</html>

使用WebSocket时需要注意以下几点:

  1. 心跳机制
  • 保持连接活跃
  • 检测连接状态
  • 及时发现断开连接
  1. 重连机制
  • 自动重连
  • 重连次数限制
  • 重连间隔
  1. 消息格式
  • 统一消息格式
  • 消息类型区分
  • 错误处理
  1. 安全性
  • 验证机制
  • 消息加密
  • 访问控制
  1. 性能优化
  • 消息压缩
  • 连接池管理
  • 负载均衡
  1. 降级方案
  • 长轮询备选
  • AJAX降级
  • 错误处理