socket.io 的工作原理

How socket.io works

我想知道 socket.io 方法如何用于发出特定事件,我读到它不像长轮询方法,而是一种可以在所有不同浏览器上工作的不同方法。 .. 客户端如何在没有长轮询请求的情况下与服务器保持联系?

我是 node.js 的新人,我想为事件驱动服务器实现我自己的系统(是的......重新发明轮子!)因为我想亲手触摸这背后的原因所以简单 "socket.io - emit()" 方法。

感谢您的帮助!

socket.io 的工作原理简述如下:

首先,socket.io 是 webSocket 之上的薄协议层,所以实际上,我们将讨论 webSocket 的工作原理。

  1. 一个 webSocket 连接从一个普通的 HTTP 请求开始,带有一个特殊的 header 集,升级 header 请求从 HTTP 协议升级到 webSocket 协议。

  2. 当服务器收到请求并看到升级时header,如果它支持该协议,则它会响应 101 响应(切换协议)和其他一些 headers。当客户端收到此响应(以及其他一些与安全相关的 header 时),然后两端将该套接字上的协议切换为 webSocket 协议。

  3. 因为 webSocket 协议被设计为持续连接,客户端和服务器都保持原始套接字打开以供将来通信,事实上,它一直保持打开状态,直到任何一方决定他们最终完成webSocket 通信通道,然后关闭套接字。

  4. 因此,套接字会长时间保持打开状态。这使任何一方都可以随时向另一方发送消息。这就是它避免轮询的方式。而不是来自客户端的临时 HTTP 请求请求服务器:"Do you have any new data for m?",客户端可以坐在那里侦听传入的消息。当服务器有新的东西要发送给客户端时,它已经有了这个打开的webSocket连接,它可以随时向客户端发送消息。

  5. Socket.io 在 webSocket 之上添加了一些特性。它添加的主要内容是:1) Auto-reconnection 如果套接字连接因任何原因丢失,2) 从一端到另一端定期 ping 以检测连接何时丢失,以及 3) 使它成为消息传递层从一端向另一端发送命名消息是微不足道的。

I would like to know how socket.io methods work for emitting a certain event, I've read that it is not like long-polling method but a different one that can work on all of different browsers

它不是长轮询,因为它在客户端期间保持套接字连接打开。这个 long-lived,打开的连接可用于仅将消息从客户端发送到服务器或从服务器发送到客户端,而无需在每次要发送时创建新连接。这适用于任何支持 webSocket 协议的浏览器。

How could a client keep-in-contact with the server without a long polling request?

webSocket 连接被设计为 long-lived 连接,而不是典型的临时 HTTP 连接。


如果您想了解更多关于 webSocket 协议本身的信息,可以在这篇 MDN 文章中看到非常好的描述:Writing webSocket Servers.

以下是打开 webSocket 的初始客户端请求示例:

GET /chat HTTP/1.1
Host: example.com:8000
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
Sec-WebSocket-Version: 13

并且,这是确认切换到 webSocket 协议的典型服务器响应:

HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=

然后,一旦协议被更改,这里的 webSocket 数据帧就是这样的:

 0               1               2               3              
 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7
+-+-+-+-+-------+-+-------------+-------------------------------+
|F|R|R|R| opcode|M| Payload len |    Extended payload length    |
|I|S|S|S|  (4)  |A|     (7)     |             (16/64)           |
|N|V|V|V|       |S|             |   (if payload len==126/127)   |
| |1|2|3|       |K|             |                               |
+-+-+-+-+-------+-+-------------+ - - - - - - - - - - - - - - - +
 4               5               6               7              
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
|     Extended payload length continued, if payload len == 127  |
+ - - - - - - - - - - - - - - - +-------------------------------+
 8               9               10              11             
+ - - - - - - - - - - - - - - - +-------------------------------+
|                               |Masking-key, if MASK set to 1  |
+-------------------------------+-------------------------------+
 12              13              14              15
+-------------------------------+-------------------------------+
| Masking-key (continued)       |          Payload Data         |
+-------------------------------- - - - - - - - - - - - - - - - +
:                     Payload Data continued ...                :
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
|                     Payload Data continued ...                |
+---------------------------------------------------------------+

Socket.io 使用 webSocket 数据帧,但在该帧的有效负载中插入了自己的消息格式,使其能够发送命名消息。