从套接字读取消息时如何获取字节序?

Posted

技术标签:

【中文标题】从套接字读取消息时如何获取字节序?【英文标题】:How to get the endianness when reading a message from socket? 【发布时间】:2014-02-13 11:45:53 【问题描述】:

我正在使用goprotocol buffersgo 程序将编码的协议缓冲区消息发送到连接到套接字的客户端。现在由于协议缓冲区没有分隔,客户端不知道要从套接字读取多少数据。

我打算在消息前面加上消息长度,一个 32 位整数。因此客户端可以读取 4 个字节,获取长度并读取完整消息。

我可以使用binary 包将整数值放入字节数组中。类似的,

binary.Write(buf, binary.LittleEndian, value)

现在的问题是,write 需要字节顺序,接收端如何知道字节顺序是什么?有没有办法在不指定明确的字节顺序的情况下处理这个问题?

【问题讨论】:

【参考方案1】:

约定是network byte order is big endian,但无论如何您的客户端和服务器都必须同意。明确指定字节顺序。

编辑:阅读 Protobuf 文档,为了保持一致性,最好使用 proto.EncodeVarintproto.DecodeVarint 在消息前写入长度。

【讨论】:

谢谢。这是有道理的。【参考方案2】:

您应该始终明确定义和记录此类事物的字节顺序(和布局)。在一般通信中,大端直接布局似乎是常态(因此 47 将是 4 个字节,十六进制值为 00 00 00 2F)。但是,您可能需要考虑特定的上下文。例如,如果您已经在谈论 protobuf,您还可以使用“varint”编码格式,在这种情况下 47 是一个单字节:2F - 许多 protobuf 实现将提供预滚动的方法来使用或产生一个 varint(否则,它是 documented here - 但可以总结为 7 位有效负载和连续位,最不重要的 7 位组在前)

【讨论】:

谢谢。 varint 有道理.. 将查看 Java API 是否支持生产和使用 varint 的方法 看来我可以使用 CodedInputStream#readRawVarint32() 来解决这个问题。 您对此有何看法:一次读取每个字节,要求 protobuf 解析它,如果失败,继续读取和解析,直到通过。这样我们就不需要在前面加上长度了。你认为这比前缀长度更好吗? @Appu 无效; protobuf 流未终止(它们被设计为可附加的)。因此,您无法确定有效负载的结束位置。如果你按照你的建议去做,你只会阅读消息的第一个字段。第二个字段将被解释为第二条消息。基本上,“不,你不能那样做”。

以上是关于从套接字读取消息时如何获取字节序?的主要内容,如果未能解决你的问题,请参考以下文章

如何从客户端套接字获取信息并在服务器上显示信息?

Java SocketChannel 吃掉我的字节

如何从Java中的字节数组中获取数据?

如何使用python套接字从html获取输入

C# Begin/EndReceive - 我如何读取大数据?

Java - 从套接字通道读取