48

因为我在更常规的基础上使用 WebSocket 连接,所以我对事情如何在幕后工作很感兴趣。因此,我研究了无休止的规范文档一段时间,但到目前为止,我真的找不到任何关于分块传输流本身的信息。

WebSocket 协议称其为数据帧(描述的是纯数据流,因此也称为非控制帧)。据我了解规范,没有定义的最大长度和没有定义的 MTU(最大传输单元)值,这反过来意味着单个 WebSocket 数据帧可能包含,通过规范(!),无限量的数据(如果我在这里错了,请纠正我,我仍然是这方面的学生)。

读完之后,我立即设置了我的小型Node WebSocket 服务器。由于我拥有丰富的Ajax历史(也在流媒体和 Comet 方面),我最初的期望是,“在传输数据时必须有某种交互模式来读取数据”。但我错了,不是吗?

我一开始很小,只有4kb的数据。

服务器

testSocket.emit( 'data', new Array( 4096 ).join( 'X' ) );

就像预期的那样,这作为一个数据块到达客户端

客户

wsInstance.onmessage = function( data ) {
    console.log( data.length ); // 4095
};

所以我增加了有效负载,实际上我再次期待,在某些时候,客户端onmessage处理程序将重复触发,有效地分块传输。但令我震惊的是,它从未发生过(node-server,在firefoxchromesafari客户端测试)。我最大的有效载荷是80 MB

testSocket.emit( 'data', new Array( 1024*1024*80 ).join( 'X' ) );

它仍然到达客户端的一个大数据块中。当然,即使您的连接非常好,这也需要一段时间。这里的问题是

  • 是否有可能将这些流分块,类似于 XHR readyState3 模式
  • 单个 ws 数据框是否有大小限制
  • websockets不应该传输如此大的有效载荷吗?(这让我再次想知道为什么没有定义的最大尺寸)

我可能仍然从错误的角度看待 WebSockets,可能不需要发送大量数据,您应该在发送之前自己逻辑地分块/拆分任何数据?

4

2 回答 2

88

首先,您需要区分浏览器中的 WebSocket协议和 WebSocket API

WebSocket 协议的帧大小限制为 2^63 个八位字节,但 WebSocket 消息可以由无限数量的帧组成。

浏览器中的 WebSocket API 不公开基于帧或流式 API,而仅公开基于消息的 API。传入消息的有效负载在提供给 JavaScript 之前总是被完全缓冲(在浏览器的 WebSocket 实现中)。

其他 WebSocket 实现的 API 可以提供对通过 WebSocket 协议传输的有效负载的基于帧或流的访问。例如,AutobahnPython就可以。您可以在此处的示例中阅读更多内容https://github.com/tavendo/AutobahnPython/tree/master/examples/twisted/websocket/streaming

披露:我是 Autobahn 的原作者,为 Tavendo 工作。

更多注意事项:

只要浏览器JS WebSocket API中没有frame/streaming API,就只能接收/发送完整的WS消息。

单个(普通)WebSocket 连接不能交错多条消息的负载。因此,即如果您使用大消息,这些消息将按顺序传递,并且您将无法在大消息仍在运行时在其间发送小消息。

有一个即将推出的 WebSocket 扩展(扩展是扩展协议的内置机制):WebSocket 多路复用。这允许在单个底层 TCP 连接上拥有多个(逻辑)WebSocket 连接,这具有多个优点。

另请注意:您现在可以从单个 JS/HTML 页面打开到单个目标服务器的多个 WS 连接(通过不同的底层 TCP)。

另请注意:您可以在应用程序层自己“分块”:以较小的 WS 消息发送您的东西,然后自己重​​新组装。

我同意,在理想的世界中,您将在浏览器中拥有消息/帧/流 API 以及 WebSocket 多路复用。这将提供所有的权力和便利。

于 2012-10-22T12:13:32.400 回答
10

RFC 6455 第 1.1 节

这就是 WebSocket 协议所提供的: [...] HTTP 轮询的替代方案,用于从网页到远程服务器的双向通信。

如前所述,WebSockets 用于网页和服务器之间的通信。请注意网页和网络浏览器之间的区别。正在使用的示例是浏览器游戏和聊天应用程序,它们交换了许多小消息。

如果您想在一条消息中发送许多 MB,我认为您没有按照预期的方式使用 WebSocket。如果您想传输文件,请使用普通旧 Http 请求执行此操作,并回答Content-Disposition让浏览器下载文件。

因此,如果您解释为什么要发送如此大量的数据,也许有人可以帮助提出比使用 WebSockets 更优雅的解决方案。

此外,客户端或服务器可能会拒绝太大的消息(尽管没有明确说明它将如何拒绝):

RFC 6455 第 10.4 节

从多个帧重新组装后,对于帧大小或总消息大小具有实现和/或平台特定限制的实现必须保护自己不超过这些限制。(例如,恶意端点可以通过发送单个大帧(例如,大小为 2**60)或通过发送长的小帧流来尝试耗尽其对等方的内存或发起拒绝服务攻击。是分段消息的一部分。)这样的实现应该对帧大小和从多个帧重组后的总消息大小施加限制。

于 2012-10-24T12:44:52.993 回答