WebSocket 教程
WebSocket 是一种在单个 TCP 连接上进行全双工通信的协议,它让浏览器和服务器之间能够建立持久化的双向通信通道。本教程将系统讲解 WebSocket 协议原理、浏览器客户端 API、以及多种语言的服务端实现。
什么是 WebSocket
WebSocket 协议于 2011 年由 IETF 标准化(RFC 6455),它解决了传统 HTTP 请求-响应模式在实时通信场景下的局限性。
HTTP 的局限性
在 WebSocket 出现之前,Web 应用实现实时通信主要依靠以下方式:
短轮询(Short Polling):客户端定时向服务器发送请求,询问是否有新数据。这种方式浪费带宽和服务器资源,因为大多数请求可能都没有新数据。
长轮询(Long Polling):客户端发送请求后,服务器保持连接打开,直到有数据可返回或超时。虽然比短轮询高效,但每次返回数据后都需要重新建立连接。
这两种方式都存在共同的问题:通信只能由客户端发起,服务器无法主动推送数据。
WebSocket 的优势
WebSocket 提供了真正的全双工通信能力:
- 全双工通信:客户端和服务器可以同时发送消息,不需要等待对方响应
- 持久连接:一次握手建立连接后,连接保持打开状态,无需重复建立
- 低延迟:消除了 HTTP 请求头的开销,消息实时传递
- 轻量级:数据帧头部只有 2-10 字节,远小于 HTTP 请求头
WebSocket 与 HTTP 的关系
WebSocket 虽然名字里带有 "Web",但它与 HTTP 是两种不同的协议。不过,WebSocket 的设计巧妙地利用了 HTTP 来完成初始握手。
握手过程
WebSocket 连接的建立始于一个 HTTP 请求,这个请求包含特殊的头部字段,表明客户端希望升级到 WebSocket 协议:
GET /chat HTTP/1.1
Host: server.example.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
Sec-WebSocket-Version: 13
服务器如果支持 WebSocket,会返回 101 Switching Protocols 响应:
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=
握手完成后,连接从 HTTP 协议切换到 WebSocket 协议,之后的通信都使用 WebSocket 的数据帧格式。
协议标识
WebSocket 使用与 HTTP 不同的 URL 方案:
ws://:非加密连接,默认端口 80wss://:加密连接(类似 HTTPS),默认端口 443
const socket = new WebSocket('ws://example.com/chat');
const secureSocket = new WebSocket('wss://example.com/chat');
适用场景
WebSocket 特别适合需要实时、双向通信的应用场景:
即时通讯
聊天应用是 WebSocket 最典型的应用场景。用户发送的消息需要实时传递给对方,同时还要接收其他用户的消息。
const socket = new WebSocket('wss://chat.example.com');
socket.onmessage = (event) => {
const message = JSON.parse(event.data);
displayMessage(message);
};
function sendMessage(text) {
socket.send(JSON.stringify({
type: 'message',
content: text,
timestamp: Date.now()
}));
}
实时数据推送
股票行情、体育比分、实时监控等场景需要服务器持续推送最新数据。
const stockSocket = new WebSocket('wss://stocks.example.com/quotes');
stockSocket.onmessage = (event) => {
const quotes = JSON.parse(event.data);
updateStockDisplay(quotes);
};
协作编辑
在线文档编辑、白板协作等应用需要实时同步多个用户的操作。
const docSocket = new WebSocket('wss://docs.example.com/collab');
docSocket.onmessage = (event) => {
const change = JSON.parse(event.data);
applyRemoteChange(change);
};
function broadcastChange(change) {
docSocket.send(JSON.stringify({
type: 'edit',
...change
}));
}
在线游戏
多人在线游戏需要低延迟的双向通信来同步玩家状态和游戏事件。
物联网(IoT)
设备状态监控、远程控制等物联网应用需要实时接收设备数据并发送控制指令。
不适用场景
WebSocket 并非万能的解决方案,以下场景可能更适合其他技术:
RESTful API:传统的 CRUD 操作仍然适合使用 HTTP REST API,因为这类请求通常是独立的、无状态的。
文件上传/下载:大文件传输更适合使用 HTTP,因为 HTTP 有更好的缓存机制和断点续传支持。
简单的数据获取:如果只需要偶尔获取数据,使用 HTTP 请求更简单直接。
需要 HTTP 缓存的场景:WebSocket 连接是持久的,无法利用 HTTP 缓存机制。
浏览器支持
WebSocket API 在现代浏览器中得到广泛支持。根据 Can I Use 的数据,WebSocket 在全球浏览器中的支持率超过 98%。
所有主流浏览器的较新版本都支持 WebSocket:
- Chrome 4+
- Firefox 4+
- Safari 5+
- Edge 12+
- Opera 11+
对于不支持 WebSocket 的旧浏览器,可以使用 Socket.IO 等库,它们会自动降级到轮询方式。
本教程内容
本教程将系统讲解 WebSocket 的各个方面:
- 协议原理:深入理解 WebSocket 协议的工作机制,包括握手过程、数据帧格式、连接状态管理等
- 浏览器客户端:学习使用 JavaScript WebSocket API,处理连接、消息、错误和关闭事件
- Node.js 服务端:使用 ws 库和 Socket.IO 构建高性能 WebSocket 服务器
- Python 服务端:使用 websockets 库和 FastAPI 实现 WebSocket 服务
- Go 服务端:使用 gorilla/websocket 构建 Go 语言 WebSocket 服务
- 最佳实践:连接管理、心跳机制、错误处理、安全考虑、性能优化等
快速开始
如果你迫不及待想体验 WebSocket,这里有一个最简单的示例:
服务端(Node.js):
const WebSocket = require('ws');
const wss = new WebSocket.Server({ port: 8080 });
wss.on('connection', (ws) => {
console.log('客户端已连接');
ws.on('message', (message) => {
console.log('收到消息:', message);
ws.send('服务器收到: ' + message);
});
ws.send('欢迎连接 WebSocket 服务器');
});
console.log('WebSocket 服务器运行在 ws://localhost:8080');
客户端(浏览器):
const socket = new WebSocket('ws://localhost:8080');
socket.onopen = () => {
console.log('连接已建立');
socket.send('你好,服务器');
};
socket.onmessage = (event) => {
console.log('收到消息:', event.data);
};
socket.onerror = (error) => {
console.error('连接错误:', error);
};
socket.onclose = () => {
console.log('连接已关闭');
};
运行服务端代码后,在浏览器控制台执行客户端代码,你就能看到 WebSocket 的基本通信效果。
小结
本章介绍了 WebSocket 的基本概念、与 HTTP 的区别、适用场景以及浏览器支持情况。WebSocket 通过在单个 TCP 连接上提供全双工通信,解决了传统 HTTP 在实时通信场景下的局限性,成为现代 Web 应用实现实时功能的重要技术。
在接下来的章节中,我们将深入探讨 WebSocket 协议的工作原理,以及如何在不同编程语言中实现 WebSocket 客户端和服务端。