跳至主要内容
版本:4.x

工作原理

Socket.IO 服务器 (Node.js) 和 Socket.IO 客户端 (浏览器、Node.js 或 其他编程语言) 之间的双向通道使用 WebSocket 连接 建立(如果可能),并将使用 HTTP 长轮询作为备用。

Socket.IO 代码库分为两个不同的层

  • 低级管道:我们称之为 Engine.IO,是 Socket.IO 内部的引擎
  • 高级 API:Socket.IO 本身

Engine.IO

Engine.IO 负责建立服务器和客户端之间的低级连接。它处理

可以在 此处 找到 Engine.IO 协议的详细版本。

参考实现的源代码(用 TypeScript 编写)可以在此处找到

传输

目前已实现两种传输

HTTP 长轮询

HTTP 长轮询传输(也简称为“轮询”)由连续的 HTTP 请求组成

  • 长时间运行的 GET 请求,用于接收来自服务器的数据
  • 短时间运行的 POST 请求,用于向服务器发送数据

由于传输的性质,连续的 emit 可能被连接起来并发送在同一个 HTTP 请求中。

WebSocket

WebSocket 传输由 WebSocket 连接 组成,它在服务器和客户端之间提供双向低延迟通信通道。

由于传输的性质,每个 emit 都发送在它自己的 WebSocket 帧中(某些 emit 甚至可能导致两个不同的 WebSocket 帧,更多信息 此处)。

握手

在 Engine.IO 连接开始时,服务器会发送一些信息

{
"sid": "FSDjX-WRwSA4zTZMALqx",
"upgrades": ["websocket"],
"pingInterval": 25000,
"pingTimeout": 20000
}
  • sid 是会话的 ID,它必须包含在所有后续 HTTP 请求的 sid 查询参数中
  • upgrades 数组包含服务器支持的所有“更好”传输的列表
  • pingIntervalpingTimeout 值用于心跳机制

升级机制

默认情况下,客户端使用 HTTP 长轮询传输建立连接。

但是,为什么呢?

虽然 WebSocket 显然是建立双向通信的最佳方式,但经验表明,由于公司代理、个人防火墙、防病毒软件等原因,并非总是能够建立 WebSocket 连接。

从用户角度来看,WebSocket 连接失败会导致实时应用程序最多等待 10 秒才能开始交换数据。这会明显损害用户体验。

总而言之,Engine.IO 首先关注可靠性和用户体验,其次关注潜在的 UX 改进和更高的服务器性能。

要升级,客户端将

  • 确保其输出缓冲区为空
  • 将当前传输置于只读模式
  • 尝试使用其他传输建立连接
  • 如果成功,关闭第一个传输

您可以在浏览器中的网络监视器中查看

Successful upgrade

  1. 握手(包含会话 ID — 此处为 zBjrh...AAAK — 用于后续请求)
  2. 发送数据(HTTP 长轮询)
  3. 接收数据(HTTP 长轮询)
  4. 升级(WebSocket)
  5. 接收数据(HTTP 长轮询,在 4. 中成功建立 WebSocket 连接后关闭)

断开连接检测

当以下情况发生时,Engine.IO 连接被视为已关闭

  • 一个 HTTP 请求(GET 或 POST)失败(例如,当服务器关闭时)
  • WebSocket 连接关闭(例如,当用户关闭浏览器中的选项卡时)
  • 在服务器端或客户端调用 socket.disconnect()

还有一种心跳机制,用于检查服务器和客户端之间的连接是否仍然正常运行

在给定的间隔(握手时发送的 pingInterval 值)内,服务器会发送 PING 数据包,客户端有几秒钟(pingTimeout 值)时间发送 PONG 数据包作为回复。如果服务器没有收到 PONG 数据包作为回复,它将认为连接已关闭。相反,如果客户端在 pingInterval + pingTimeout 内没有收到 PING 数据包,它将认为连接已关闭。

断开连接原因列在 此处(服务器端)和 此处(客户端端)。

Socket.IO

Socket.IO 在 Engine.IO 连接之上提供了一些额外的功能

可以在 此处 找到 Socket.IO 协议的详细版本。

参考实现的源代码(用 TypeScript 编写)可以在此处找到