Skip to content

WebSocket 原理与面试题解析

一、WebSocket 出现前的实时场景解决方案

1. 常见的实时应用场景

  • 金融领域: 股票 K 线图、实时报价。
  • 即时通讯: 网页聊天室、在线客服。
  • 系统通知: 紧急警报(如地震预警)、重要消息推送。
  • 实时数据: 票务系统的余票信息、抢购活动的实时库存。

这些场景的共同特点是 对数据的实时性要求非常高

2. 问题的根源:HTTP 的请求-响应模式

传统的 Web 通信基于 HTTP 协议,其核心是 请求-响应模式

  • 工作流程: 必须由客户端(浏览器)首先发起请求,服务器才能返回响应。
  • 核心限制: 服务器无法主动向客户端推送(Push)数据。

以聊天为例:

  1. 用户 A 通过 HTTP 请求将消息 "你好" 发送给服务器。
  2. 服务器响应用户 A,表示消息已收到。
  3. 服务器 无法 主动将消息推送给用户 B,因为它不能主动发起连接。
  4. 只有当用户 B 向服务器发起请求时,服务器才能在响应中把消息"你好"捎带给用户 B。但问题是,用户 B 不知道何时会有新消息,因此也不知道何时应该发起请求。

3. 旧方案一:短轮询 (Short Polling)

短轮询是一种模拟实时通信的“话唠式”方案。

  • 原理: 客户端使用定时器(如 setInterval),每隔一个很短的时间(例如 1-2 秒)就向服务器发送一次 HTTP 请求,询问是否有新数据。

  • 流程图解:

    Client:           Server:
      | --(有新消息吗?)--> |
      | <--(暂时没有)---- | (完成一次HTTP请求/响应,TCP连接关闭)
      |                  |
    (等待1秒)             |
      |                  |
      | --(有新消息吗?)--> |
      | <--(暂时没有)---- | (完成一次HTTP请求/响应,TCP连接关闭)
      |                  |
    (等待1秒)             |
      |                  |
      | --(有新消息吗?)--> |
      | <--(有!给你数据) | (完成一次HTTP请求/响应,TCP连接关闭)
      | ...              |
  • 优点:

    • 实现简单,兼容性好。
  • 缺点:

    • 产生大量无意义请求: 大多数请求可能都是空轮询,服务器并没有新数据,浪费带宽和服务器资源。
    • 频繁建立和关闭连接: 每次请求都伴随着 TCP 的三次握手和四次挥手,开销巨大。
    • 实时性不佳: 消息的延迟取决于轮询间隔。间隔太短则服务器压力大,间隔太长则消息延迟高。

4. 旧方案二:长轮询 (Long Polling)

长轮询是短轮询的改进版,旨在减少无效请求。

  • 原理: 客户端发送一个 HTTP 请求到服务器。服务器收到后,如果有新消息则立即响应;如果没有新消息,则 挂起(Hold) 这个连接,直到有新消息或连接超时为止。客户端在收到响应或请求超时后,立即发起下一次长轮询请求。

  • 流程图解:

    Client:           Server:
      | --(有新消息吗?)--> |
      |                  | (服务器收到请求,但没有新消息,保持连接)
      |                  |
      | ...等待...       | (一段时间后,服务器有了新消息)
      |                  |
      | <--(有!给你数据) | (服务器响应,本次连接关闭)
      |                  |
      | --(有新消息吗?)--> | (客户端立即发起下一次请求)
      |                  |
      | ...等待...       |
  • 优点:

    • 显著减少了无效的请求次数,节省了带宽。
    • 实时性相对较高,一旦有数据就能立即响应。
  • 缺点:

    • 服务器资源占用: 服务器需要长时间挂起连接,如果客户端数量庞大,会对服务器造成较大的内存和连接数压力。
    • 连接超时问题: HTTP 请求有超时限制,如果长时间没有新消息,连接会因超时而中断。客户端需要处理超时逻辑,立即重新发起请求,这会产生一些无意义的连接。

二、WebSocket 详解

WebSocket 从根本上解决了问题,它是一种全新的、独立的协议。

1. 核心原理:全双工通信

  • HTTP: 半双工(Half-duplex)。数据传输有固定的先后顺序(请求->响应)。
  • WebSocket: 全双工(Full-duplex)。连接一旦建立,通信双方地位平等,可以在任意时刻互相发送数据,互不干扰。

WebSocket 建立在 TCP 协议之上,充分利用了 TCP 的全双工通信能力,解决了 HTTP 协议中服务器无法主动推送消息的限制。

2. WebSocket 连接过程

WebSocket 的生命周期分为两个阶段:握手阶段通信阶段

  1. 建立 TCP 连接: 和 HTTP 一样,首先需要通过 TCP 的三次握手建立底层连接。
  2. WebSocket 握手: TCP 连接建立后,客户端会通过一个特殊的 HTTP 请求与服务器进行“握手”,协商从 HTTP 协议升级到 WebSocket 协议。
  3. 数据传输: 握手成功后,连接升级为 WebSocket 连接,双方可以开始自由地进行全双工通信。
  4. 关闭 TCP 连接: 当一方请求关闭或连接中断时,通过 TCP 的四次挥手关闭连接。

3. WebSocket 的优缺点

  • 优点:

    • 真正的实时性: 服务器可以主动推送数据,延迟极低。
    • 减少开销: 只需一次握手即可建立持久连接,后续数据传输无需再发送冗余的 HTTP 头。
    • 更好的性能: 协议开销小,数据帧格式轻量,传输效率高。
  • 缺点:

    • 兼容性: 作为 HTML5 新增协议,一些非常古老的浏览器可能不支持。
    • 服务器资源: 维持一个长连接需要占用服务器一定的内存和连接资源。对于消息量稀少的场景,可能会造成资源浪费。

4. WebSocket 能否取代 Ajax?

不能。 它们适用于不同的场景。

  • Ajax/HTTP: 适用于“请求-响应”模式明确的场景,如获取文章列表、提交表单等。这些操作通常是短暂、一次性的,用完即弃,无需维持长连接。
  • WebSocket: 适用于需要高实时性、频繁双向通信的场景,如聊天、游戏、协同编辑等。

优化思考: 在一个必须使用 WebSocket 的页面(如聊天页面),为了充分利用已建立的持久连接,理论上可以将页面内其他的 Ajax 请求也通过 WebSocket 来完成,从而避免发起新的 HTTP 请求。但这样做会大大增加程序设计的复杂性(前后端都需要适配两种通信逻辑),因此在实践中很少使用。

三、WebSocket 握手过程 (面试重点)

握手阶段的本质是 “借用 HTTP 协议来完成协议升级的协商”

1. 客户端请求 (Handshake Request)

客户端发起一个特殊的 HTTP/1.1 GET 请求。

  • 请求地址: 协议名由 http:// 变为 ws://(或 https 对应 wss://)。

    • ws://your.server.com/path
    • wss://your.server.com/path (WSS 运行在 TLS/SSL 之上,是加密的)
  • 关键请求头:

    http
    GET /chat HTTP/1.1
    Host: server.example.com
    Connection: Upgrade
    Upgrade: websocket
    Sec-WebSocket-Version: 13
    Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
    • Connection: Upgrade: 告诉服务器,客户端希望升级协议。
    • Upgrade: websocket: 明确指出希望升级到 websocket 协议。
    • Sec-WebSocket-Version: 13: 指定 WebSocket 协议版本,目前常用的是 13。
    • Sec-WebSocket-Key: 一个 Base64 编码的随机字符串,用作简单的“暗号”,防止一些意外的或恶意的连接。

2. 服务器响应 (Handshake Response)

如果服务器同意升级协议,会返回一个特殊的响应。

  • 状态码: 101 Switching Protocols,表示服务器同意切换协议。

  • 关键响应头:

    http
    HTTP/1.1 101 Switching Protocols
    Connection: Upgrade
    Upgrade: websocket
    Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=
    • Connection: Upgrade & Upgrade: websocket: 同样返回这两个头,确认协议升级。
    • Sec-WebSocket-Accept: 这是服务器对客户端Sec-WebSocket-Key的“回令”。它的值是服务器将客户端的 Sec-WebSocket-Key 与一个固定的“魔术字符串” (258EAFA5-E914-47DA-95CA-C5AB0DC85B11) 拼接后,计算 SHA-1 哈希,再进行 Base64 编码得到的。客户端会验证这个值,确认服务器是真正的 WebSocket 服务器。

握手成功后,该 HTTP 连接的生命周期结束,TCP 通道被 WebSocket 协议接管,后续通信都遵循 WebSocket 的帧格式,不再有 HTTP 的请求和响应。

四、相关面试题汇总

1. 什么是 WebSocket 协议?请简述一下。

WebSocket 是 HTML5 提供的一种在单个 TCP 连接上进行全双工通信的协议。它是一个持久化的连接协议,与 HTTP 不同,它允许服务器主动向客户端推送数据。其连接过程首先通过 HTTP 协议进行一次握手,握手成功后协议升级为 WebSocket,之后的数据交换都通过这个持久的 TCP 通道进行,实现了真正的实时通信。

2. WebSocket 与传统 HTTP 相比有什么优势?

  • 通信模式: WebSocket 是全双工通信,服务器可以主动推送消息,解决了 HTTP 服务器只能被动响应的限制。相比之下,HTTP 必须由客户端发起请求。
  • 性能开销: WebSocket 建立连接后,后续数据传输的头部开销非常小,而 HTTP 每个请求都带有完整的、通常是冗余的头部信息。
  • 实时性: WebSocket 提供了真正的实时数据传输能力,而传统的解决方案如短轮询和长轮询都有延迟高、消耗资源等问题。长轮询虽然实时性较好,但会长时间占用服务器连接资源。

3. 前端如何实现即时通信?

主要有三种方案:

  1. 短轮询 (Short Polling): 客户端定时向服务器发送请求。实现简单,但实时性差、资源浪费严重。
  2. 长轮询 (Long Polling): 客户端发送请求后,服务器会挂起连接直到有数据或超时。相比短轮询有较大改进,但仍存在服务器资源占用和连接超时的问题。
  3. WebSocket: 目前实现即时通信的最佳方案。它通过一次握手建立持久的全双工连接,允许服务器主动、实时地向客户端推送数据,性能好,开销小。

4. 简述 WebSocket 的握手过程。

WebSocket 的握手过程借用了 HTTP 协议。

  1. 客户端请求: 客户端向服务器发起一个 HTTP GET 请求,请求头中包含 Connection: UpgradeUpgrade: websocket,表示请求升级协议。同时会带上一个随机生成的 Sec-WebSocket-Key 作为标识。
  2. 服务器响应: 服务器如果同意升级,会返回状态码为 101 Switching Protocols 的响应,响应头中也包含 Connection: UpgradeUpgrade: websocket。同时,服务器会使用客户端的 Sec-WebSocket-Key 按照约定算法计算出一个 Sec-WebSocket-Accept 值并返回给客户端进行验证。
  3. 握手完成: 客户端验证通过后,握手成功,HTTP 连接升级为 WebSocket 连接,双方可以开始自由通信。