凌峰创科服务平台

如何搭建JS WebSocket服务器?

WebSocket 是一种在单个 TCP 连接上进行全双工通信的协议,它允许服务器主动向客户端推送数据,非常适合实时应用,如在线聊天、实时数据仪表盘、多人在线游戏等。

如何搭建JS WebSocket服务器?-图1
(图片来源网络,侵删)

我们将使用 Node.js 的内置 http 模块和 ws 这个非常流行且功能强大的第三方库来创建服务器。


第一步:环境准备

  1. 安装 Node.js: 确保你的系统已经安装了 Node.js,你可以从 Node.js 官网 下载并安装。
  2. 创建项目目录:
    mkdir websocket-server
    cd websocket-server
  3. 初始化项目:
    npm init -y
  4. 安装 ws:
    npm install ws

第二步:创建一个简单的 WebSocket 服务器

创建一个名为 server.js 的文件,并输入以下代码:

// server.js
// 1. 引入必要的模块
const http = require('http');
const WebSocket = require('ws');
// 2. 创建一个 HTTP 服务器,WebSocket 服务器将依附于此
const server = http.createServer((req, res) => {
  // 这个回调函数处理普通的 HTTP 请求
  // 对于 WebSocket 连接,这个回调不会被触发
  console.log('收到一个 HTTP 请求');
  res.writeHead(200, { 'Content-Type': 'text/plain' });
  res.end('你好,这是一个 HTTP 服务器。');
});
// 3. 创建 WebSocket 服务器,并附加到 HTTP 服务器上
const wss = new WebSocket.Server({ server });
// 4. 监听 'connection' 事件,当有新的客户端连接时触发
wss.on('connection', (ws) => {
  console.log('新的客户端连接!');
  // 5. 监听 'message' 事件,当收到客户端消息时触发
  ws.on('message', (message) => {
    console.log(`收到消息: ${message}`);
    // 6. 将收到的消息再发回给客户端(回显)
    // ws.send(message); 
    // 或者,服务器可以向所有连接的客户端广播消息
    wss.clients.forEach((client) => {
      if (client.readyState === WebSocket.OPEN) {
        client.send(`服务器广播: ${message}`);
      }
    });
  });
  // 7. 监听 'close' 事件,当客户端断开连接时触发
  ws.on('close', () => {
    console.log('客户端断开连接。');
  });
  // 8. 服务器主动向新连接的客户端发送一条欢迎消息
  ws.send('欢迎连接到 WebSocket 服务器!');
});
// 9. 启动 HTTP 服务器,监听指定的端口
const PORT = 8080;
server.listen(PORT, () => {
  console.log(`WebSocket 服务器正在运行,监听端口: ${PORT}`);
  console.log(`请访问 http://localhost:${PORT} 来测试 HTTP 服务,`);
  console.log(`WebSocket 连接通常由客户端库(如浏览器中的 JavaScript)建立,`);
});

代码解释:

  1. 引入模块: http 用于创建基础服务器,ws 是核心 WebSocket 库。
  2. 创建 HTTP 服务器: WebSocket 连接是通过 HTTP 协议进行“握手”升级的,所以必须有一个 HTTP 服务器作为基础。
  3. 创建 WebSocket 服务器 (wss): new WebSocket.Server({ server }) 将 WebSocket 服务器绑定到我们刚刚创建的 HTTP 服务器上,所有发往此服务器的请求,如果符合 WebSocket 升级协议,就会被 wss 处理。
  4. connection 事件: 这是服务器最重要的入口,每当一个新的客户端成功建立 WebSocket 连接,这个事件就会被触发,并传入一个 ws 对象,代表该客户端的连接实例。
  5. message 事件: 在 connection 事件中,我们为每个 ws 对象监听 message 事件,当该客户端发送消息时,这个事件就会被触发。
  6. ws.send(): 通过这个方法,服务器可以向单个客户端发送消息。
  7. wss.clients: 这是一个 Set 对象,包含了所有已连接的客户端,我们可以遍历它,向所有连接的客户端广播消息。
  8. close 事件: 当客户端正常断开连接或网络异常导致连接断开时,此事件会被触发。
  9. server.listen(): 启动服务器,使其在指定端口上监听请求。

第三步:创建一个简单的客户端(HTML + JavaScript)

为了测试我们的服务器,我们需要一个客户端,创建一个 index.html 文件:

<!-- index.html -->
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">WebSocket 客户端</title>
    <style>
        body { font-family: sans-serif; }
        #messages { border: 1px solid #ccc; padding: 10px; height: 300px; overflow-y: scroll; margin-bottom: 10px; }
        #input { width: 80%; padding: 5px; }
        button { padding: 5px 10px; }
    </style>
</head>
<body>
    <h1>WebSocket 聊天客户端</h1>
    <div id="messages"></div>
    <div>
        <input type="text" id="input" placeholder="输入消息...">
        <button id="sendButton">发送</button>
    </div>
    <script>
        // 1. 获取 DOM 元素
        const messagesDiv = document.getElementById('messages');
        const input = document.getElementById('input');
        const sendButton = document.getElementById('sendButton');
        // 2. 创建 WebSocket 连接
        // 注意:ws:// 协议用于非加密连接,wss:// 用于加密连接
        const ws = new WebSocket('ws://localhost:8080');
        // 3. 监听连接成功事件
        ws.onopen = () => {
            console.log('成功连接到服务器!');
            appendMessage('系统: 连接成功。');
        };
        // 4. 监听收到消息事件
        ws.onmessage = (event) => {
            console.log('收到服务器消息:', event.data);
            appendMessage(event.data);
        };
        // 5. 监听连接关闭事件
        ws.onclose = () => {
            console.log('与服务器断开连接。');
            appendMessage('系统: 连接已关闭。');
        };
        // 6. 监听错误事件
        ws.onerror = (error) => {
            console.error('WebSocket 发生错误:', error);
            appendMessage(`错误: ${error.message}`);
        };
        // 7. 发送消息的函数
        function sendMessage() {
            const message = input.value.trim();
            if (message) {
                ws.send(message); // 通过 WebSocket 发送消息
                input.value = ''; // 清空输入框
            }
        }
        // 8. 绑定发送按钮的点击事件
        sendButton.addEventListener('click', sendMessage);
        // 9. 绑定输入框的回车事件
        input.addEventListener('keypress', (event) => {
            if (event.key === 'Enter') {
                sendMessage();
            }
        });
        // 辅助函数:将消息添加到消息区域
        function appendMessage(message) {
            const messageElement = document.createElement('div');
            messageElement.textContent = message;
            messagesDiv.appendChild(messageElement);
            messagesDiv.scrollTop = messagesDiv.scrollHeight; // 自动滚动到底部
        }
    </script>
</body>
</html>

客户端代码解释:

  1. new WebSocket('ws://localhost:8080'): 在浏览器中创建 WebSocket 连接,指向我们运行的服务器地址。
  2. ws.onopen: 连接成功后触发,通常在这里可以发送第一条消息。
  3. ws.onmessage: 收到服务器发来的消息时触发,event.data 包含消息内容。
  4. ws.onclose: 连接关闭时触发。
  5. ws.onerror: 连接发生错误时触发。
  6. ws.send(): 客户端向服务器发送消息。

第四步:运行和测试

  1. 启动服务器: 在你的终端中,确保在 websocket-server 目录下,运行:

    如何搭建JS WebSocket服务器?-图2
    (图片来源网络,侵删)
    node server.js

    你会看到 WebSocket 服务器正在运行,监听端口: 8080 的提示。

  2. 打开客户端: 用浏览器打开 index.html 文件,打开浏览器的开发者工具(F12),在 Console 标签页中你应该会看到 "成功连接到服务器!" 的日志。

  3. 测试通信:

    • 在输入框中输入任何消息,点击“发送”或按回车。
    • 在消息区域,你会看到服务器广播回来的消息。
    • 打开两个浏览器窗口,都访问 index.html,在一个窗口中发送消息,另一个窗口也能收到,这证明了“广播”功能。

进阶:实现房间(Room)功能

在实际应用中,我们通常需要将用户分组到不同的“房间”中进行通信,而不是所有用户都在一个大房间里。ws 库没有内置房间功能,但我们可以很轻松地自己实现。

如何搭建JS WebSocket服务器?-图3
(图片来源网络,侵删)

修改 server.js 如下:

// server.js (房间版)
const http = require('http');
const WebSocket = require('ws');
const server = http.createServer();
const wss = new WebSocket.Server({ server });
// 使用一个 Map 来存储房间,键是房间名,值是该房间内的客户端 Set
const rooms = new Map();
wss.on('connection', (ws) => {
  console.log('新的客户端连接!');
  // 客户端发送的第一条消息必须是加入房间的请求,格式为: { action: 'join', room: 'room1' }
  ws.on('message', (message) => {
    const data = JSON.parse(message);
    console.log('收到消息:', data);
    if (data.action === 'join') {
      const roomName = data.room;
      if (!rooms.has(roomName)) {
        rooms.set(roomName, new Set());
      }
      rooms.get(roomName).add(ws);
      ws.currentRoom = roomName; // 为客户端连接对象附加当前房间信息
      ws.send(`你已成功加入房间: ${roomName}`);
      console.log(`客户端加入房间: ${roomName}`);
    } else if (data.action === 'send') {
      const roomName = data.room;
      const msg = data.message;
      if (rooms.has(roomName)) {
        rooms.get(roomName).forEach((client) => {
          if (client.readyState === WebSocket.OPEN) {
            client.send(`房间 ${roomName} 的消息: ${msg}`);
          }
        });
      }
    }
  });
  ws.on('close', () => {
    console.log('客户端断开连接。');
    // 客户端断开时,将其从所有房间中移除
    for (const [roomName, clients] of rooms.entries()) {
      if (clients.has(ws)) {
        clients.delete(ws);
        console.log(`客户端已从房间 ${roomName} 移除,`);
      }
    }
  });
  ws.send('请通过 JSON 格式发送加入房间的请求, {"action": "join", "room": "room1"}');
});
const PORT = 8080;
server.listen(PORT, () => {
  console.log(`支持房间的 WebSocket 服务器正在运行,监听端口: ${PORT}`);
});

修改客户端以支持房间

修改 index.html 中的 sendMessage 函数,让它能发送 JSON 格式的消息:

// 在 index.html 的 <script> 标签内修改 sendMessage 函数和添加房间输入
// ... (前面的代码保持不变) ...
// 在 body 中添加房间输入
<div>
    <label for="roomInput">房间:</label>
    <input type="text" id="roomInput" value="room1" placeholder="输入房间名...">
</div>
<div>
    <input type="text" id="input" placeholder="输入消息...">
    <button id="sendButton">发送</button>
</div>
// ... (后面的代码保持不变,直到 sendMessage 函数) ...
// 修改 sendMessage 函数
function sendMessage() {
    const message = input.value.trim();
    const roomName = document.getElementById('roomInput').value.trim() || 'general'; // 默认房间
    if (message) {
        // 发送 JSON 格式的消息
        const data = {
            action: 'send',
            room: roomName,
            message: message
        };
        ws.send(JSON.stringify(data));
        input.value = '';
    }
}
// ... (后面的代码保持不变) ...

你可以启动新版的服务器,然后用两个浏览器窗口测试,确保两个窗口加入同一个房间(比如都输入 room1),这样它们就能互相通信了,如果一个窗口加入 room1,另一个加入 room2,它们就不会收到彼此的消息。


  • 核心库: 使用 ws 库可以非常方便地创建 Node.js WebSocket 服务器。
  • 工作流程: HTTP 服务器 -> WebSocket 握手 -> 建立 ws 连接 -> 通过事件 (onopen, onmessage, onclose, onerror) 进行通信。
  • 广播与单播: wss.clients 用于广播,ws.send() 用于单播。
  • 扩展性: 对于更复杂的功能(如房间、认证),可以通过在 message 事件中解析自定义消息格式(如 JSON)来实现。

希望这个详细的指南能帮助你理解和使用 Node.js 创建 WebSocket 服务器!

分享:
扫描分享到社交APP
上一篇
下一篇