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

我们将使用 Node.js 的内置 http 模块和 ws 这个非常流行且功能强大的第三方库来创建服务器。
第一步:环境准备
- 安装 Node.js: 确保你的系统已经安装了 Node.js,你可以从 Node.js 官网 下载并安装。
- 创建项目目录:
mkdir websocket-server cd websocket-server
- 初始化项目:
npm init -y
- 安装
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)建立,`);
});
代码解释:
- 引入模块:
http用于创建基础服务器,ws是核心 WebSocket 库。 - 创建 HTTP 服务器: WebSocket 连接是通过 HTTP 协议进行“握手”升级的,所以必须有一个 HTTP 服务器作为基础。
- 创建 WebSocket 服务器 (
wss):new WebSocket.Server({ server })将 WebSocket 服务器绑定到我们刚刚创建的 HTTP 服务器上,所有发往此服务器的请求,如果符合 WebSocket 升级协议,就会被wss处理。 connection事件: 这是服务器最重要的入口,每当一个新的客户端成功建立 WebSocket 连接,这个事件就会被触发,并传入一个ws对象,代表该客户端的连接实例。message事件: 在connection事件中,我们为每个ws对象监听message事件,当该客户端发送消息时,这个事件就会被触发。ws.send(): 通过这个方法,服务器可以向单个客户端发送消息。wss.clients: 这是一个Set对象,包含了所有已连接的客户端,我们可以遍历它,向所有连接的客户端广播消息。close事件: 当客户端正常断开连接或网络异常导致连接断开时,此事件会被触发。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>
客户端代码解释:
new WebSocket('ws://localhost:8080'): 在浏览器中创建 WebSocket 连接,指向我们运行的服务器地址。ws.onopen: 连接成功后触发,通常在这里可以发送第一条消息。ws.onmessage: 收到服务器发来的消息时触发,event.data包含消息内容。ws.onclose: 连接关闭时触发。ws.onerror: 连接发生错误时触发。ws.send(): 客户端向服务器发送消息。
第四步:运行和测试
-
启动服务器: 在你的终端中,确保在
websocket-server目录下,运行:
(图片来源网络,侵删)node server.js
你会看到
WebSocket 服务器正在运行,监听端口: 8080的提示。 -
打开客户端: 用浏览器打开
index.html文件,打开浏览器的开发者工具(F12),在 Console 标签页中你应该会看到 "成功连接到服务器!" 的日志。 -
测试通信:
- 在输入框中输入任何消息,点击“发送”或按回车。
- 在消息区域,你会看到服务器广播回来的消息。
- 打开两个浏览器窗口,都访问
index.html,在一个窗口中发送消息,另一个窗口也能收到,这证明了“广播”功能。
进阶:实现房间(Room)功能
在实际应用中,我们通常需要将用户分组到不同的“房间”中进行通信,而不是所有用户都在一个大房间里。ws 库没有内置房间功能,但我们可以很轻松地自己实现。

修改 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 服务器!
