【问题标题】:WebSocket protocol binary data endiannessWebSocket 协议二进制数据字节序
【发布时间】:2013-01-31 21:25:42
【问题描述】:

我正在编写基于 WebSocket 协议的服务器和客户端。

服务器是使用 Python 和 Twisted 制作的。

现在我可以将二进制数据从服务器发送到客户端并返回,唯一的问题是,根据某些消息来源,从浏览器发送的二进制数据的字节序是基于机器字节序的。我想确认一下,是真的吗?

如果这是真的,那么我是否应该以某种方式检查客户端有什么字节序并使用他的字节序从/向他读取/发送数据?检查客户端字节顺序的最佳方法是什么,只需从客户端发送

var view_buffer = new UInt8Array(new ArrayBuffer(1));
view_buffer[0] = 1;

这个数据,并在服务器上检查它是否返回 1 或 128?

【问题讨论】:

  • 请注意,字节中的一位不会告诉您字节序。位很少被处理器交换,并且在通过网络发送时肯定不会交换。一个更好的例子是使用两个字节。

标签: javascript python websocket endianness


【解决方案1】:

根据RFC 6455

多字节长度量以网络字节顺序表示。

网络字节顺序是大端。服务器和客户端都应该使用这个字节顺序,不管它们的原生顺序是什么。

在 Python 中,struct module 可用于通过 '>' 说明符确保正确的字节顺序。我不确定它会如何在 Javascript 中完成。

【讨论】:

  • 我将消息类型打包成 2 个字节(前 4 位是一种类型,后 12 位是子类型)。 # 将类型值左移 12 位 message_type_value = message_type << 12 # 替代子类型值 message_types_value = message_type_value | message_subtype。我检查了它,当我从服务器上的客户端值 4096(这意味着类型 1,子类型 0)发送时,我使用大端序解压缩 (276, 0),使用小端序它是 (1,0),看起来我不能强制浏览器使用大端序
  • @RafałŁużyński,见stackoverflow.com/questions/9283093/…
  • 谢谢,看起来当我将数据拆分为 8 位值时它可以工作。但我接受了 Alnitak 的回答,因为他给了我更详细的答案。
【解决方案2】:

要检查字节顺序,您需要发送至少两个字节的值。

您不能仅通过发送单个字节来检查,因为此时已经为您整理了位级字节序。

因此,字节序仅对字节交换(如果需要)以及如果您尝试使用特定于字节序的规则打包单个位(例如在 C 中使用位域时)很重要。

如果您的问题与您自己在 WebSocket 有效负载中携带的消息有关,通常的过程是自己选择一个字节顺序,然后执行您必须执行的任何打包或解包操作以将本机字节顺序转换为您的首选字节顺序.我知道的大多数协议都使用大端序,也就是“网络顺序”。

因此,如果您有一个 16 位的值,请自己使用移位和按位运算符将其转换为两个 8 位字节,然后先发送最高字节,然后发送第二个字节。在服务器端,反转该过程。大多数服务器端语言都可以很容易地将值从网络顺序转换为本地字节顺序。

【讨论】:

  • 感谢您的回答。请看我对 Mark Ransom 答案的评论。
  • @RafałŁużyński 您是否关心构成 WebProtocol 协议本身的消息,或您的数据该协议中的传输?
  • 我按照你说的做了。我在客户端将数据拆分为 8 位值,然后将其发送到服务器。但是在服务器上我没有做任何逆转过程。我只是用 big-endian 解压数据并且值是正确的 (struct.unpack('>H', data))。可以吗?
【解决方案3】:

字节序仅与由多于一个字节组成的数据类型相关。由于您使用的是 uint8 字节序数组,因此并不重要。

【讨论】:

  • 我没有说我只使用 UInt8。我只是想发送它进行字节序检查,但你是对的,1 字节没关系。
  • 我只是参考您的评论和 UInt8Aray。 uint8 在大端和小端系统上完全相同。如果您想通过传输测试数据来检测字节顺序,您至少需要一个 uint16。 big endian 1 将变为 little endian 256 反之亦然:0x0001 <-> 0x0100
【解决方案4】:

RFC 6455 中有关于 close 消息顺序的注释:

如果有正文,正文的前两个字节必须是一个 2 字节无符号整数(按网络字节顺序),表示具有值 /code/ 在第 7.4 节中定义的状态代码。

因此,如果您要在 WS 消息中使用二进制数据,该协议通常会希望您使用大端序。我想这不是强制性的,通过。

如果您想允许其中任何一个,您可以在消息的开头添加一个幻数。那将是 2 个不同的字节,例如 (('M'

正如 Mark Ransom 在评论中指出的那样,可以从 JavaScript 以任一字节序发送数据,但必须交换所有字节可能很烦人。因此,具有指示当前字节顺序的 2 字节值通常是解决问题的一个非常好的方法。接收数据的服务器可以检查这两个字节并相应地交换short、int、long int数据。

【讨论】:

    【解决方案5】:

    让客户端向服务器发送一条 126 字节或更多(但小于 65535)(例如 200)字节的文本消息。 Payload_Length 字段将为 126。

    然后检查扩展有效负载长度的下两个字节,以确定客户端是否以大端(可能)发送它,或者客户端是否搞砸并以小端格式发送。

    对于大端,紧挨着 8 位有效负载长度的字节(应该是 126 表示接下来的两个字节实际上包含实际有效负载长度)应该是 16 位长度的最高有效字节。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-01-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-04-11
      • 2010-09-17
      • 1970-01-01
      相关资源
      最近更新 更多