分块WebSocket传输

时间:2012-10-22 11:20:30

标签: javascript node.js websocket specifications

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

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

阅读完之后,我立即设置了我的小 Node WebSocket服务器。由于我有一个强大的 Ajax 历史(也在流媒体和Comet上),我的期望原来就像是,“在传输数据时必须有某种交互模式来读取数据”。但那里我错了,不是吗?

我从 4kb 的数据开始很小。

服务器

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

和预期的一样,它作为一个数据块到达客户端

客户端

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

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

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

它仍然存在于客户端上的一个大数据块中。当然,即使你有一个非常好的连接,这需要一段时间。这里的问题是

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

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

2 个答案:

答案 0 :(得分:80)

首先,您需要在 browsers 中区分WebSocket 协议和WebSocket API

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

浏览器中的WebSocket API不会公开基于帧的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中没有框架/流API,您就只能接收/发送完整的WS消息。

单个(普通)WebSocket连接无法交错多条消息的有效负载。因此,如果您使用大型邮件,那些邮件将按顺序发送,并且您仍然无法在大型邮件仍处于运行状态时在其间发送小邮件。

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

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

另请注意:您可以在应用程序层中自行“分块”:将您的内容发送到较小的WS消息中,然后重新自行组装。

我同意,在一个理想的世界中,你在浏览器和WebSocket多路复用中都有消息/帧/流API。这将提供所有的力量和便利。

答案 1 :(得分:10)

  

RFC 6455 Section 1.1

     

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

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

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

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

此外,客户端或服务器可能会拒绝过大的消息(虽然没有明确声明 它会拒绝):

  

RFC 6455 Section 10.4

     

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