分块WebSocket传输

因为我在更经常的基础上使用WebSocket连接,所以我对引擎盖下的工作感兴趣。 所以我在一段时间内深入了解无尽的规格说明文档,但到目前为止,我还是无法find有关分stream传输stream本身的东西

WebSocket协议将其称为dataframe (它描述纯数据stream,因此也称为非控制帧 )。 就我所了解的规范而言,没有定义的最大长度和没有定义的MTU(最大传输单元)值,这又意味着单个WebSocketdataframe可能按规范(!)包含无限数量的数据(如果我错了,请纠正我,我仍然是这个学生)。

读完之后,我立即安装了我的小型节点 WebSocket服务器。 由于我有很强的Ajax历史(也是在stream媒体和Comet上),我的期望本来就是“ 在数据传输时必须有一种交互式的读取方式 ”。 但是我错了,不是吗?

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

服务器

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

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

客户

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

所以我增加了有效负载,而且我实际上又在onmessage ,在某个时候,客户端的onmessage处理程序将重复发射,从而有效地传输数据。 但令我震惊的是,它从来没有发生( 节点服务器 ,在FirefoxChromeSafari客户端testing)。 我最大的有效载荷是80 MB

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

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

  • 是否有可能将这些数据stream块化,类似于XHR readyState3模式
  • 单个ws数据框有没有大小限制
  • websockets不应该转移这么大的有效载荷? (这将使我想知道为什么没有一个定义的最大尺寸)

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

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

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

浏览器中的WebSocket API不公开基于帧或streamAPI的API,但只是基于消息的API。 传入消息的负载总是在提供给JavaScript之前完全缓冲(在浏览器的WebSocket实现中)。

其他WebSocket实现的API可以对通过WebSocket协议传输的有效载荷提供基于帧或stream的访问。 例如, AutobahnPython呢 。 你可以阅读更多的例子在这里https://github.com/tavendo/AutobahnPython/tree/master/examples/twisted/websocket/streaming

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

更多的考虑:

只要浏览器JS WebSocket API中没有框架/stream式API,您只能接收/发送完整的WS消息。

单个(普通)WebSocket连接不能交错多个消息的有效负载。 也就是说,如果你使用大量的消息,那么这些消息就会按顺序发送,而且当一个大消息还在运行时,你将不能发送小消息。

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

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

还要注意:你可以在应用层做“自我分析”:把你的东西发送到较小的WS消息中,自己重新组装。

我同意,在一个理想的世界里,你会在浏览器中join消息/帧/streamAPI和WebSocket多路复用。 这将给所有的权力和方便。

RFC 6455第1.1节 :

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

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

如果你想在一个消息中发送多个MB,我认为你没有按照他们想要的方式使用WebSockets。 如果你想传输文件,那么使用普通的旧Http请求,用Content-Disposition来回答,让浏览器下载一个文件。

所以,如果你解释为什么你要发送如此大量的数据,也许有人可以帮助拿出比使用WebSockets更优雅的解决scheme。

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

RFC 6455第10.4节 :

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