WebSocket 是如何压缩消息的?

Posted

技术标签:

【中文标题】WebSocket 是如何压缩消息的?【英文标题】:How does WebSocket compress messages? 【发布时间】:2013-10-18 09:12:08 【问题描述】:

JSON.stringify 显然不是很节省空间。例如,[123456789,123456789] 占用 20+ 个字节,而它可能只需要大约 5 个字节。websocket 在发送到流之前会压缩其 JSON 吗?

【问题讨论】:

【参考方案1】:

WebSocket 本质上只是一组 TEXT 或 BINARY 数据的框架。

它自己不执行压缩。

但是,WebSocket 规范允许扩展,并且已经有各种压缩扩展(其中之一的正式规范已最终确定)。

截至今天(2018 年 8 月),接受的压缩规范为 permessage-deflate

一些在野外看到的扩展:

permessage-deflate - 使用 deflate 压缩整个消息的正式规范的名称,与 websocket 帧的数量无关。 x-webkit-deflate-frame - 一种早期提议的压缩方法,用于压缩每个原始 websocket 数据帧。已被 Chrome 和 Safari 使用。 (现已在 Chrome 和 Safari 中弃用) perframe-deflate - 上述压缩的重命名版本。已被各种 websocket 服务器实现以及briefly showed up in various WebKit based clients 使用。 (在现代浏览器中完全弃用,但仍然出现在各种 WebSocket 客户端库中)

值得注意的是,permessage-deflate 扩展是 PMCE(每消息压缩扩展)系列中的第一个,最终将包括其他压缩方案(ones being discussed 是 permessage-bzip2permessage-lz4permessage-snappy )

【讨论】:

正如 Joakim 提到的,permessage-deflate 尚未正式发布。 FWIW,Chromium 拥有它(但您需要手动启用)并且他们很快“打算发货”:groups.google.com/a/chromium.org/forum/#!topic/blink-dev/… 感谢@Joakim Erdfelt,但是 permessage-deflate 使用 gzip 吗?我正在尝试通过 websocket 管道压缩 gzip 数据。 @NiCkNewman 扩展名permessage-deflatedeflate 算法,gzip 不同。如果您自己在扩展之外执行此操作,请注意您只能使用 BINARY 消息(用于 websocket 协议),因为压缩的 TEXT 消息将违反 rfc-6455 规范(要求 TEXT 消息为 UTF-8) 您能否根据今天的更新更新您的答案(我的意思是 2016 年底)【参考方案2】:

websocket 在发送到流之前会压缩它的 JSON 吗?

简短的回答是:有时,但你不能依赖它

正如 Joakim Erdfelt 所说,Websocket 连接支持文本和二进制消息。

JSON 只是传输数据的一种方式,具有多功能性和易用性的优势(但就空间而言是一种浪费)。

您可以使用 Websocket API 轻松传输二进制数据,从而消除带宽开销,但需要考虑其他问题(例如端序、字长、解析等)。

许多浏览器还支持 Websocket 消息压缩作为 Websocket 协议的扩展(尽管服务器可能不支持该扩展)。

使用Sec-WebSocket-Extensions HTTP 标头协商扩展。协商通常由客户端/服务器实现,不提供公共 API 来控制它们。

直到 2015 年,有许多方法和实现在野外,但 since December 2015 RFC 7692 是消息压缩的唯一真正竞争者,事情要清楚得多。

RFC 7692 在将整个消息包装(也可能是分段)到 Websocket“数据包”之前对其进行压缩,使其比以前的一些压缩方案更容易实现。

当前草案提供了permessage-foo 压缩协商方案(其中foo 是请求/支持的压缩)。

我自己只体验过permessage-deflate 扩展。

请注意扩展协商是可选的,这意味着即使您的服务器支持扩展,通常也允许潜在的网络客户端协商连接而不进行压缩。

此外,RFC 7692 支持选择性压缩,这意味着一些消息可能会被压缩,而另一些则不会被压缩...

...例如,[123456789,123456789] 可能会按原样发送,因为它的长度表明它可能不值得进行压缩。

支持permessage-deflate (RFC 7692),2017 年 8 月 8 日:

这是 cmets 中信息的组合,最后更新于 2017 年 8 月 8 日。

如果我错过了什么,请在此处添加并更新日期。

已知浏览器支持

自 32 开始的 Chrome 自 37 年以来的 Mozilla Firefox Safari - 不支持(10.1.2 似乎使用x-webkit-deflate-frame) Microsoft Edge - 自版本 40 起不受支持

已知服务器支持

Crossbar.io(高速公路) wspy Tornado node.js 和 Ruby 上的 Faye SwiftWebSocket(只读?) WS-RS(锈)

【讨论】:

自 Google Chrome 32 和 Mozilla Firefox 37 以来似乎支持 permessage-deflate。截至 2017 年 8 月(Edge 40),我没有看到 Microsoft Edge 支持它的证据。在 Python 服务器端,截至 2017 年 8 月,似乎只有 Crossbar.io (Autobahn)、wspy 和 Tornado 支持它。 @JohnZwinck - 添加到当前状态,Safari 使用x-webkit-deflate-frame,在服务器端,Faye 在 node.js 上支持permessage-defalte @JohnZwinck 我将信息添加到答案中,以便将来的编辑者轻松更新。 评论者:不要为更新原始帖子中的信息而感到紧张。这就是 *** 的一部分 :) 自 2020 年 1 月起 Safari 似乎无法正常工作(Firefox 可以)。 Safari:“与 'ws://192.1.1.100:8080/ws' 的 WebSocket 连接失败:无法压缩帧”【参考方案3】:

您可以使用Unishox 压缩技术来压缩通过 Websockets 发送的文本。然而,这并没有与规范集成,实现者负责压缩一侧并解压缩另一侧。

Unishox 通过根据流行符号的已知频率(熵编码)为给定字符集中的每个字母分配固定的无前缀代码来实现压缩。它还分别对重复的字母集进行编码(字典编码)。对于 Unicode 字符,使用增量编码。更多信息请见in this article。

到目前为止,它已在C 和javascript 中实现。

免责声明:我是 Unishox 的开发者。

【讨论】:

【参考方案4】:

Websockets 发送原始字节。 他们不知道也不关心这些字节代表什么。

如果你想压缩数据,你需要自己压缩,然后再通过网络发送。

请注意,Chrome 支持使用 gzip 进行 websocket 连接。 (假设您的服务器也这样做)

【讨论】:

gzip 会压缩像这样的数字字符串吗(我猜不是)? Chrome 或其他地方(其他浏览器)中没有“gzip”WebSocket 压缩。 @oberstet:你确定吗? ***.com/questions/11646680/… gzip 是一种文件格式,它使用 deflate 作为压缩算法。 deflate 是 LZ77 和 Huffman 编码的组合。 (旧的)每帧压缩 WS 扩展和新的每消息 WS 压缩扩展使用 deflate。

以上是关于WebSocket 是如何压缩消息的?的主要内容,如果未能解决你的问题,请参考以下文章

使用rabbitmq广播模式来处理集群下的websocket消息推送

带有异步计时器的 Python 异步 websocket 客户端

如何编写一个 websocket 客户端

如何在 Spring Boot 中禁用 Tomcat 的 permessage-deflate WebSocket 压缩?

web socket 入门

MessageWebsocket升级请求中如何使用Sec-Websocket-Extensions