Node.js实现WebSocket教程

Node.js实现WebSocket教程

1. WebSocket简介

WebSocket是一种在单个TCP连接上提供全双工通信的协议,允许服务器和客户端之间进行实时、双向通信。本教程将详细讲解如何在Node.js中实现WebSocket。

2. 技术选型

我们将使用ws库来实现WebSocket服务器,并结合express创建Web应用。

2.1 安装依赖
复制代码
# 创建项目目录
mkdir nodejs-websocket-demo
cd nodejs-websocket-demo

# 初始化项目
npm init -y

# 安装依赖
npm install express ws uuid

依赖说明:

  • express: Web应用框架
  • ws: WebSocket服务器实现
  • uuid: 生成唯一标识符

3. 项目结构

复制代码
nodejs-websocket-demo/
│
├── public/
│   ├── index.html
│   └── client.js
├── server.js
└── package.json

4. 详细实现

4.1 WebSocket服务器 (server.js)
复制代码
const express = require('express');
const http = require('http');
const WebSocket = require('ws');
const { v4: uuidv4 } = require('uuid');

const app = express();
const server = http.createServer(app);
const wss = new WebSocket.Server({ server });

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

// 静态文件服务
app.use(express.static('public'));

// WebSocket连接处理
wss.on('connection', (ws) => {
  // 为每个客户端分配唯一ID
  const clientId = uuidv4();
  
  // 存储客户端连接
  clients.set(clientId, ws);

  // 发送客户端ID
  ws.send(JSON.stringify({
    type: 'connection',
    clientId: clientId
  }));

  // 广播新用户连接
  broadcast({
    type: 'userJoined',
    clientId: clientId,
    message: `用户 ${clientId} 已加入聊天`
  }, clientId);

  // 消息处理
  ws.on('message', (message) => {
    try {
      const parsedMessage = JSON.parse(message);
      
      switch(parsedMessage.type) {
        case 'chat':
          handleChatMessage(clientId, parsedMessage);
          break;
        case 'typing':
          handleTypingNotification(clientId, parsedMessage);
          break;
        default:
          console.log('未知消息类型:', parsedMessage.type);
      }
    } catch (error) {
      console.error('消息解析错误:', error);
    }
  });

  // 连接关闭处理
  ws.on('close', () => {
    // 移除客户端
    clients.delete(clientId);

    // 广播用户离开
    broadcast({
      type: 'userLeft',
      clientId: clientId,
      message: `用户 ${clientId} 已离开聊天`
    }, clientId);
  });
});

// 聊天消息处理
function handleChatMessage(senderId, message) {
  broadcast({
    type: 'chat',
    clientId: senderId,
    message: message.message
  }, senderId);
}

// 输入状态通知
function handleTypingNotification(senderId, message) {
  broadcast({
    type: 'typing',
    clientId: senderId,
    isTyping: message.isTyping
  }, senderId);
}

// 广播消息
function broadcast(message, excludeClientId = null) {
  clients.forEach((client, clientId) => {
    if (client.readyState === WebSocket.OPEN && clientId !== excludeClientId) {
      client.send(JSON.stringify(message));
    }
  });
}

// 服务器启动
const PORT = process.env.PORT || 3000;
server.listen(PORT, () => {
  console.log(`WebSocket服务器运行在 ${PORT} 端口`);
});
4.2 客户端HTML (public/index.html)
复制代码
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>WebSocket聊天室</title>
    <style>
        body { 
            font-family: Arial, sans-serif; 
            max-width: 600px; 
            margin: 0 auto; 
            padding: 20px; 
        }
        #chat-messages {
            height: 300px;
            overflow-y: scroll;
            border: 1px solid #ccc;
            padding: 10px;
            margin-bottom: 10px;
        }
    </style>
</head>
<body>
    <div id="chat-messages"></div>
    <input type="text" id="message-input" placeholder="输入消息">
    <button id="send-btn">发送</button>

    <script src="client.js"></script>
</body>
</html>
4.3 客户端JavaScript (public/client.js)
复制代码
const socket = new WebSocket('ws://localhost:3000');
let clientId = null;

const chatMessages = document.getElementById('chat-messages');
const messageInput = document.getElementById('message-input');
const sendBtn = document.getElementById('send-btn');

// WebSocket事件处理
socket.addEventListener('open', (event) => {
  appendMessage('系统', '连接成功');
});

socket.addEventListener('message', (event) => {
  const message = JSON.parse(event.data);

  switch(message.type) {
    case 'connection':
      clientId = message.clientId;
      appendMessage('系统', `您的ID是: ${clientId}`);
      break;
    case 'chat':
      appendMessage(message.clientId, message.message);
      break;
    case 'userJoined':
    case 'userLeft':
      appendMessage('系统', message.message);
      break;
    case 'typing':
      handleTypingNotification(message);
      break;
  }
});

socket.addEventListener('close', (event) => {
  appendMessage('系统', '连接已关闭');
});

// 发送消息
sendBtn.addEventListener('click', sendMessage);
messageInput.addEventListener('keypress', (e) => {
  if (e.key === 'Enter') {
    sendMessage();
  }
});

function sendMessage() {
  const message = messageInput.value.trim();
  if (message) {
    socket.send(JSON.stringify({
      type: 'chat',
      message: message
    }));
    appendMessage(clientId, message);
    messageInput.value = '';
  }
}

// 消息追加到聊天窗口
function appendMessage(sender, text) {
  const messageEl = document.createElement('div');
  messageEl.innerHTML = `<strong>${sender}:</strong> ${text}`;
  chatMessages.appendChild(messageEl);
  chatMessages.scrollTop = chatMessages.scrollHeight;
}

// 处理打字状态通知
function handleTypingNotification(message) {
  // 可以在这里实现打字状态提示
}

5. 运行项目

复制代码
# 启动服务器
node server.js

# 访问 http://localhost:3000

6. 功能特点

  1. 实时双向通信
  2. 唯一客户端标识
  3. 广播消息机制
  4. 连接/断开事件处理
  5. 聊天消息和系统通知

7. 性能与扩展建议

  1. 生产环境考虑使用Redis等外部存储管理WebSocket连接
  2. 增加身份验证机制
  3. 实现消息持久化
  4. 使用负载均衡

8. 安全注意事项

  1. 使用WSS(WebSocket Secure)
  2. 实现连接速率限制
  3. 验证和过滤消息内容
  4. 防止跨站WebSocket劫持
相关推荐
超级赛博搬砖工1 小时前
并发、多线程和HTTP连接之间有什么关系?
网络·网络协议·http
5G微创业3 小时前
Python / Node.js 调用短视频去水印 API 完整示例(含 SDK)
python·node.js·音视频·api·sdk·短视频
2401_891957314 小时前
简单了解传输层协议UDP
网络·网络协议·udp
一棵星4 小时前
WebSocket 长连接不稳?一次完整的排查与修复之旅
网络·websocket·网络协议
寒水馨4 小时前
macOS下载、安装electron-v43.2.0(附安装包electron-v43.2.0-darwin-arm64.zip)
javascript·macos·electron·node.js·跨平台·桌面应用开发·开源框架
JackieDYH4 小时前
WebSocket-不同平台封装-Hooks和使用案例
网络·websocket·网络协议
hoLzwEge18 小时前
拯救低效调试!code-inspector-plugin 让代码定位如虎添翼
前端·前端框架·node.js
牛马工作号1 天前
Wi‑Fi 完全指南:从 802.11 协议到 Wi‑Fi 7、AC+AP 与 Mesh 工程组网
网络·网络协议·智能路由器
lakers-w1 天前
websocket实现系统聊天功能
websocket
Geek-Chow1 天前
ALB SSL policy conflict (AWS Load Balancer Controller)
网络协议·ssl·aws