WebSocket是基于流还是基于包的协议?

16

假设我有一个通过WebSocket通信的服务器和客户端。它们每次都发送一些数据块,不同的数据块可能有不同的长度。

那么问题来了,如果服务器在一次调用中发送了一个数据块,客户端是否保证能在一个 message 回调函数中接收到它呢?反之亦然。也就是说,WebSocket 是否具有内置的“打包”功能,以便在传输过程中我无需担心我的数据是否分散在多个回调函数中或者没有被完整接收?


https://dev59.com/Q2Ei5IYBdhLWcg3wseKA,https://dev59.com/HWcs5IYBdhLWcg3wPxrN#13011241 - Pacerier
2个回答

15
理论上,WebSocket协议是一种基于消息的协议。但请注意...
  • WebSocket消息由一个或多个帧组成。
  • 帧可以是完整的帧或分片帧。
  • 消息本身在协议中没有任何长度指示,只有帧存在长度指示。
  • 由于该协议允许63位长度指示符,因此帧的有效负载长度可达到9,223,372,036,854,775,807字节。
  • 分片的主要目的是在不必缓冲消息的情况下,允许发送始大小未知的消息。

因此...

单个WebSocket“消息”可以由无限数量的9,223,372,036,854,775,807字节的片段组成。

这可能会使实现难以通过其API始终将完整的消息传递给您...

因此,虽然在一般情况下,您不需要手动对消息进行分帧,因为WebSocket协议是一种基于消息的协议。但您使用的API可能具有消息大小限制(以允许它保证作为单个块交付消息)或可能提供流接口以允许无限大小的消息。

我曾在标准化过程中抱怨过这个问题,请参见此处


1
旧的抱怨(大约在2011年),其中大部分观点现在已经在各种真实世界的websocket实现中变得无关紧要、无效或得到了解决。 - Joakim Erdfelt
1
好的,我想我们会同意不同意,除非你想在相关博客文章中发表评论并指出它现在不正确的地方;然后我们可以讨论。实现可以并且确实可以采用自己的解决方法(例如消息大小限制),但这并不会削弱协议规范允许上述行为的事实,而且在我看来,这是不幸的,当时应该/可以处理。 - Len Holgate
我猜这里讨论的所有人都是我所说的网络和WebSocket专家;) 但是我想指出一件事情给其他读者:我认为值得区分API和协议。 WebSocket API可以在不同的级别上公开WebSocket:每个消息,每个帧或流式传输。即使使用流式API,实现也可以公开消息边界。无论如何,WebSocket协议本身基于消息(和帧)。并且它要求保留消息边界-但不是帧边界。 - oberstet
确实。然而,原始问题有点含糊不清,它询问了实现将如何向用户代码传递消息的方式。 - Len Holgate

10

WebSocket是一种基于消息的协议,如果您将一块数据作为WebSocket消息的有效负载发送,接收方将会收到一个带有该准确数据块作为有效负载的单独WebSocket消息。


我对于2022年Firefox和Chrome的这种行为的具体确认很感兴趣。你恰好知道吗? - Todd Freed
1
是的,仍然是这样,因为浏览器中可用于任何JavaScript的API仍然是相同的,而该API是基于WebSocket消息的,您用于观察WebSocket连接的JavaScript回调会在每个WebSocket消息上触发。据我所知,没有API可以获取单个WebSocket帧、单个TCP/TLS段或单个IP数据包。 - oberstet

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接