VoociiBlog
HomeBlogAI TrendingPortfolioBooksLinksToolsAbout


Voocii© 2026. Built with Next.js & tRPC.
GitHubXEmailRSS

浅入浅出 WebSocket:实时通信革命——专线双工

Techrick-hayekrick-hayek2024年12月1日

在早期的 Web 开发中,网页上的数据几乎都是“静止”的。你想看最新的球赛比分、股票行情或者聊天消息,必须手动刷新一下网页。

如今,聊天软件、多人联机游戏、实时股票看板等应用在网页端已经随处可见。它们能像本地客户端一样,毫秒级地实时推送数据。这一切的幕后功臣,就是 WebSocket。

这里用通俗易懂的语言,带你搞明白 WebSocket 的前世今生、工作原理以及开发实践。


1. 为什么我们需要 WebSocket?

在了解 WebSocket 之前,我们先来看看如果没有它,我们该怎么实现“实时数据更新”。

传统的 HTTP 局限性:单向与无状态

HTTP 协议是一个请求-响应模型。这意味着:

  • 只能由客户端发起:服务器像个傲娇的店员,你不开口问,他绝对不会主动把商品推给你。
  • 头部开销大:每次 HTTP 请求都要携带大量的 Header(如 User-Agent, Cookie 等),如果只是为了传递一个“是/否”的状态,数据包中 99% 都是无用的头部。

为了在网页上实现“实时推送”,开发者们曾想出了几种妥协手段:

方案拟人化比喻优缺点
短轮询 (Short Polling)每隔 2 秒给餐馆打个电话:
“我外卖好了吗?”
“没好,挂了。”
又过 2 秒:“我外卖好了吗?”
优点:实现极简单。
缺点:服务器压力极大,充斥着无用连接,延迟高。
长轮询 (Long Polling)给餐馆打电话:“外卖好了告诉我,没好别挂电话。”
餐馆让电话通着,直到外卖好了才说话。
挂断后客户端立刻再拨过去。
优点:比短轮询延迟低。
缺点:依然需要频繁建立连接,服务器需要挂起大量线程,极其消耗资源。

因此,WebSocket 应运而生。它打破了 HTTP 单向通信的限制,建立了一条全双工、长连接、持久化的通信专线。


2. 什么是 WebSocket?

WebSocket 是一种在单个 TCP 连接上进行全双工Full-Duplex通信的协议。它在 2011 年被 IETF 定为标准(RFC 6455)。

Note

什么是全双工(Full-Duplex)?

  • 单工:只能单向传输(如:收音机广播,只能它说你听)。
  • 半双工:双方都可以说话,但同一时刻只能有一方说(如:对讲机,说话时必须按住按钮,对方只能听)。
  • 全双工:双方可以同时发送和接收数据(如:打电话,大家可以一起抢着说话)。

3. WebSocket 的工作原理:握手升级

WebSocket 并不是凭空产生的,它在建立连接时非常聪明地借用了 HTTP 的肩膀。这个过程被称为握手(Handshake)。

握手四部曲:

  1. 客户端发起普通的 HTTP 请求,但特殊的请求头表明:“我想把这个连接升级为 WebSocket”。
  2. 服务器同意升级,返回 HTTP 101 Switching Protocols。
  3. 握手成功,原来的 HTTP 通信协议关闭,双方转而使用 WebSocket 协议。
  4. 专线接通,双方可以随意互发消息,直到有一方主动关闭。

握手的请求与响应细节:

客户端请求 (HTTP Upgrade)服务端响应 (101 Switching)
GET /chat HTTP/1.1HTTP/1.1 101 Switching Protocols
Host: example.comUpgrade: websocket
Upgrade: websocket
(表明想要升级协议)
Connection: Upgrade
(同意升级协议)
Connection: UpgradeSec-WebSocket-Accept: HSmrc0sMlYJ...
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==

握手成功后,传输的数据将不再被包裹在厚重的 HTTP 报文里,而是使用 WebSocket 独有的轻量级数据帧(Frame)。每个数据帧的头部开销仅为 2 到 10 字节,相比 HTTP 动辄数 KB 的 Header,开销近乎为零!


4. 动手实践:写一个简易的聊天室

光说不练假把式,我们用几行代码在本地搭建一个最基础的 WebSocket 服务。

后端代码:Node.js (使用 ws 库)

首先,在项目里安装包:

npm install ws

创建 server.js 并写入:

const { WebSocketServer } = require('ws');

// 在 8080 端口启动 WebSocket 服务
const wss = new WebSocketServer({ port: 8080 });

console.log('WebSocket server is running on ws://localhost:8080');

wss.on('connection', (ws) => {
  console.log('有新的客户端连接成功!');

  // 监听客户端发来的消息
  ws.on('message', (message) => {
    console.log(`收到客户端消息: ${message}`);
    
    // 向客户端回送一条确认消息
    ws.send(`服务器已收到你的消息,内容是:"${message}"`);
  });

  // 监听连接断开
  ws.on('close', () => {
    console.log('客户端连接断开');
  });
});

前端代码:浏览器原生 JavaScript API

在 HTML 或浏览器控制台(F12)中运行以下代码:

// 1. 创建 WebSocket 实例,连接到我们刚刚启动的服务器
const socket = new WebSocket('ws://localhost:8080');

// 2. 监听连接打开事件
socket.onopen = (event) => {
  console.log('成功连接到服务器!正在发送测试数据...');
  
  // 3. 发送数据给服务器
  socket.send('哈喽,我是浏览器!');
};

// 4. 监听接收服务器消息事件
socket.onmessage = (event) => {
  console.log(`收到服务器的回复: ${event.data}`);
};

// 5. 监听关闭连接事件
socket.onclose = (event) => {
  console.log('连接已关闭');
};

5. 生产环境中的高频踩坑点与最佳实践

在写 Demo 时,WebSocket 看起来非常完美。但如果你要把它推向千万用户的生产环境,必须要面对以下三大挑战:

Tip

最佳实践一:心跳检测机制(Heartbeat / Ping-Pong)

在实际网络环境中,防火墙、网关、运营商路由等节点如果发现一个 TCP 连接长时间没有数据传输,会自作主张地将其切断(称之为“死连接”)。

解决办法:客户端和服务器需要约定一个“心跳”机制。例如客户端每隔 15 秒向服务器发送一个轻量级的 Ping 包,服务器收到后回一个 Pong 包。如果在 30 秒内没有任何响应,说明连接已死,客户端应立刻发起重连。

Warning

最佳实践二:多服务器集群下的消息分发(Redis Pub/Sub)

当单台服务器装不下你的在线用户时,你会部署多台服务器。但问题来了:

  • 用户 A 连接在 服务器 1 上。
  • 用户 B 连接在 服务器 2 上。
  • 用户 A 给用户 B 发消息,服务器 1 找不到用户 B 的 WebSocket 句柄!

解决办法:引入一个中间层(如 Redis 的发布/订阅订阅模式,或者是 RabbitMQ/Kafka)。服务器 1 收到消息后,将其“发布”到 Redis 频道,所有服务器共同订阅这个频道。哪个服务器拥有用户 B 的连接,哪个服务器负责把消息送达。

Important

最佳实践三:强制使用 WSS(Secure WebSocket)

类似于传统的 http:// 升级为 https://,WebSocket 也有加密安全版 wss://。

在生产环境中,请一律使用 wss://。因为除了数据加密防窃听外,许多中间代理服务器(如部分旧路由器)不认识普通的 ws:// 协议,会直接拦截该流量;而 wss:// 数据在 TLS 加密通道中传输,中间节点只能将其作为常规加密流量转发,从而大大提高了连接成功率。


6. 动画演示

👉 点击此处在新页面中打开动画演示

7. 总结:HTTP 与 WebSocket 怎么选?

WebSocket 的出现并不是为了完全取代 HTTP,而是对 HTTP 无法高效处理实时数据的有力补充。

  • 如果你的应用:主要是静态数据展示、文章阅读、表单提交,或者对实时性要求极低的场景,请继续使用 HTTP/HTTPS。
  • 如果你的应用:需要低延迟的双向信息传递(如:弹幕互动、即时聊天、协作文档编辑、多玩家游戏、物联网控制等),那么 WebSocket 是你不二的选择。

Comments (0)

No comments yet. Be the first!

On this page
  • 1. 为什么我们需要 WebSocket?
  • 2. 什么是 WebSocket?
  • 3. WebSocket 的工作原理:握手升级
  • 4. 动手实践:写一个简易的聊天室
  • 5. 生产环境中的高频踩坑点与最佳实践
  • 6. 动画演示
  • 7. 总结:HTTP 与 WebSocket 怎么选?