socket.io 是如何工作的
Posted
技术标签:
【中文标题】socket.io 是如何工作的【英文标题】:How socket.io works 【发布时间】:2016-11-13 13:26:12 【问题描述】:我想知道 socket.io 方法如何工作以发出某个事件,我读过它不像长轮询方法,而是一种可以在所有不同浏览器上工作的不同方法......客户端在没有长轮询请求的情况下与服务器保持联系?
我是 node.js 的新手,我想为事件驱动服务器实现我自己的系统(是的......重新发明***!)因为我想用手触摸这个如此简单的“socket.js”背后的原因。 io - emit()" 方法。
感谢您的帮助!
【问题讨论】:
如果您想“重新发明***”以了解发生了什么,我建议您浏览server-side 和client-side 存储库的源代码...仅供参考,socket.emit
的实现这一点都不容易,实际上依赖于几个后备方案,其中一个确实包括长轮询,如果不存在像 WebSockets 这样的其他传输。
你读过这个问题***.com/questions/16719282/how-does-socket-io-work 吗?
@Wahib 感谢您的评论。是的,我读过这个问题,但我想问一些更实际的问题,比如 jfriend00 指出的
@Patrick 谢谢,但我发现 socket.io 存储库对我来说就像一团糟,我还是 node.js 的新手,我还不明白制作用于导出的模块或只是实现......所以我现在更喜欢问它在“解释理论”中是如何工作的:)
【参考方案1】:
简而言之,socket.io 的工作原理如下:
首先,socket.io 是 webSocket 之上的一个薄协议层,所以说真的,我们将讨论 webSocket 的工作原理。
一个 webSocket 连接从一个普通的 HTTP 请求开始,该请求带有一个特殊的标头集,即 Upgrade 标头,它请求从 HTTP 协议升级到 webSocket 协议。
当服务器收到请求并看到升级标头时,如果它支持该协议,则它会以 101 响应(切换协议)和其他一些标头进行响应。当客户端收到此响应(以及其他一些与安全性相关的标头)时,两端都会将该套接字上的协议切换到 webSocket 协议。
因为 webSocket 协议设计为持续连接客户端和服务器,所以保持原始套接字打开以供将来通信,事实上,它一直保持打开状态,直到任何一方决定它们最终完成了 webSocket 通信通道然后关闭套接字。
因此,套接字会长时间保持打开状态。这使得任何一方都可以随时向另一方发送消息。这就是它避免轮询的方式。而不是来自客户端的临时 HTTP 请求询问服务器:“你有 m 的任何新数据吗?”,客户端可以坐在那里监听传入的消息。当服务器有新的东西要发送给客户端时,它已经有这个打开的 webSocket 连接,它可以随时向客户端发送一条消息。
Socket.io 在 webSocket 之上添加了一些功能。它添加的主要内容是:1)如果套接字连接由于任何原因丢失,则自动重新连接,2)从一端到另一端的定期 ping 以检测连接何时丢失,以及 3)一个消息传递层,使得它变得微不足道从一端发送命名消息到另一端。
我想知道 socket.io 方法是如何工作的 事件,我读过它不像长轮询方法,而是 一种可以在所有不同浏览器上运行的不同浏览器
它不是长轮询,因为它在客户端期间保持套接字连接打开。这种长期开放的连接可用于将消息从客户端发送到服务器或从服务器发送到客户端,而无需在每次要发送时都创建新连接。这适用于任何支持 webSocket 协议的浏览器。
客户端如何在没有长时间的情况下与服务器保持联系 轮询请求?
webSocket 连接被设计为长寿命连接,而不是典型的临时 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 数据帧,但在该帧的有效负载中插入了自己的消息格式,允许它发送命名消息。
【讨论】:
添加协议和数据帧示例。以上是关于socket.io 是如何工作的的主要内容,如果未能解决你的问题,请参考以下文章
socket.io 身份验证与共享会话数据,io.use() 如何工作