Skip to content

HTML5 - WebSocket

WebSockets 代表了 Web 通信技术的一项重大进步,它通过单个持久的 TCP 连接,实现了客户端(通常是 Web 浏览器)与服务器之间的全双工、双向通信。

与传统的 HTTP 请求-响应周期或长轮询等技术不同,WebSockets 允许客户端和服务器一旦连接建立后,可以在任何时候相互发送消息。这使得它们非常适合实时应用,如聊天、实时通知、协作编辑、多人游戏和金融数据流。

连接首先以标准的 HTTP 请求(一个 ‘Upgrade’ 请求)开始,如果成功,则转换为 WebSocket 协议(ws:// 或用于安全连接的 wss://)。

HTML5 提供了一个 JavaScript API 来与 WebSocket 连接交互。核心是 WebSocket 对象。

// 创建一个新的 WebSocket 连接
// 使用 wss:// 进行安全连接(推荐!)
const socket = new WebSocket('wss://your-websocket-server.com/path');
// 可选:指定子协议(服务器必须支持其中一个)
// const socket = new WebSocket('wss://your-server.com/chat', ['json', 'xml']);

这里,url 指定 WebSocket 服务器的端点。可选的 protocols 参数可以是一个字符串或字符串数组,用于指定客户端理解的子协议。

WebSocket 实例的关键属性:

属性描述
socket.readyState只读属性,表示连接状态:
0 (CONNECTING): 连接尚未建立。
1 (OPEN): 连接已建立,可以通信。
2 (CLOSING): 连接正在关闭。
3 (CLOSED): 连接已关闭或无法打开。
socket.bufferedAmount只读属性。使用 send() 排队但尚未传输到网络的字节数。
socket.protocol只读字符串。如果服务器选择了子协议,则为该子协议。
socket.url只读字符串。WebSocket 连接到的 URL。

事件处理器对于与 WebSocket 连接交互至关重要:

事件事件处理属性描述
opensocket.onopen当连接成功建立时触发(readyState 变为 1)。
messagesocket.onmessage当客户端从服务器接收到数据时触发。事件对象有一个 data 属性,包含接收到的消息(可以是 string, Blob, 或 ArrayBuffer)。
errorsocket.onerror通信中发生错误时触发(例如,连接无法建立)。
closesocket.onclose当连接关闭时触发(无论是主动关闭还是由于错误)。事件对象提供 code 和 reason 属性。

用于管理连接的方法:

方法描述
socket.send(data)通过连接向服务器传输数据(字符串、Blob、ArrayBuffer 等)。如果连接未打开,则抛出错误。
socket.close([code], [reason])关闭 WebSocket 连接。可以提供可选的 code(状态码)和 reason(字符串)。

此示例演示了如何连接、发送/接收消息以及处理事件。(需要一个运行在 wss://echo.websocket.org 的 WebSocket 服务器,这是一个公共的回显服务器)。

<!DOCTYPE html>
<html>
<head>
<title>WebSocket Client Example</title>
</head>
<body>
<h1>WebSocket Test</h1>
<input type="text" id="messageInput" placeholder="Enter message...">
<button onclick="sendMessage()">Send Message</button>
<button onclick="closeConnection()">Close Connection</button>
<div id="output" style="margin-top: 10px; border: 1px solid #ccc; padding: 10px; min-height: 100px;"></div>
<script>
const messageInput = document.getElementById('messageInput');
const outputDiv = document.getElementById('output');
let socket;
function log(message) {
const p = document.createElement('p');
p.textContent = message;
outputDiv.appendChild(p);
console.log(message);
}
function connectWebSocket() {
if (!("WebSocket" in window)) {
log("WebSocket NOT supported by your Browser!");
return;
}
// 使用 wss:// 连接到公共回显服务器以确保安全
const wsUrl = 'wss://echo.websocket.org/';
log(`Attempting to connect to ${wsUrl}...`);
socket = new WebSocket(wsUrl);
socket.onopen = function(event) {
log("WebSocket connection opened.");
// 如果需要,可以在这里发送初始消息
// socket.send("Hello Server!");
};
socket.onmessage = function(event) {
log(`Message received from server: ${event.data}`);
// 如果需要,处理不同类型的消息
// const message = JSON.parse(event.data);
};
socket.onclose = function(event) {
log(`WebSocket connection closed. Code: ${event.code}, Reason: ${event.reason || 'N/A'}`);
socket = null; // 清除引用
};
socket.onerror = function(error) {
log(`WebSocket Error: ${error.message || 'Unknown error'}`);
console.error('WebSocket Error:', error);
};
}
function sendMessage() {
if (!socket || socket.readyState !== WebSocket.OPEN) {
log("WebSocket is not connected.");
return;
}
const message = messageInput.value;
if (!message) return;
log(`Sending message: ${message}`);
socket.send(message); // 作为字符串发送
// 或者发送 JSON:
// socket.send(JSON.stringify({ type: 'chat', text: message }));
messageInput.value = ''; // 清空输入字段
}
function closeConnection() {
if (socket && socket.readyState === WebSocket.OPEN) {
log("Closing WebSocket connection...");
socket.close(1000, "Client closed connection"); // 正常关闭
} else {
log("WebSocket is not open or already closed.");
}
}
// 页面加载时自动连接
connectWebSocket();
</script>
</body>
</html>

WebSocket 客户端需要一个兼容的服务器,该服务器能理解 WebSocket 协议握手和消息帧。

实现 WebSocket 服务器涉及处理初始的 HTTP Upgrade 请求、管理连接以及处理传入/传出消息。针对不同的后端语言(如 Node.js、Python、Java、C#、Go 等)存在各种库和框架,以简化服务器创建。

概念性的 Node.js 服务器示例(使用 ‘ws’ 库)

Section titled “概念性的 Node.js 服务器示例(使用 ‘ws’ 库)”

这是一个使用流行的 Node.js ws 库的简单示例。你需要安装 Node.js 并运行 npm install ws。

// server.js (Node.js 示例)
const WebSocket = require('ws');
const wss = new WebSocket.Server({ port: 8080 }); // 选择一个端口
console.log('WebSocket server started on port 8080');
wss.on('connection', function connection(ws) {
console.log('Client connected.');
// 发送欢迎消息
ws.send('Welcome to the WebSocket server!');
// 处理从客户端接收到的消息
ws.on('message', function incoming(message) {
console.log('Received from client: %s', message);
// 将消息回显给客户端
ws.send(`Server received: ${message}`);
// 或者广播给所有客户端(示例)
/*
wss.clients.forEach(function each(client) {
if (client !== ws && client.readyState === WebSocket.OPEN) {
client.send(`Broadcast: ${message}`);
}
});
*/
});
// 处理客户端断开连接
ws.on('close', function close() {
console.log('Client disconnected.');
});
// 处理错误
ws.on('error', function error(err) {
console.error('WebSocket error:', err);
});
});

要运行此代码,请将其保存为 server.js,安装 ‘ws’ 库(npm install ws),然后运行 node server.js。然后,更新客户端示例中的 wsUrl 为 ws://localhost:8080(或者如果服务器配置了 TLS/SSL,使用 wss://,这在生产环境中强烈推荐)。

像 Socket.IO 这样的库构建于 WebSockets 之上(并提供回退方案),以提供房间、自动重连和更简单的广播等附加功能,但它们也需要使用 Socket.IO 客户端库。