我可以安全地忽略网络中的字节顺序吗?


24

我正在开发服务器-客户端应用程序,其中客户端将在Windows上运行,服务器可能在Linux上运行。也许以后再将客户端移植到Mac和Linux,但还没有。

如今,所有家用计算机都在低端字节序上运行。我用Google搜索了一会儿,但是我真的找不到运行在big-endian上的设备列表。据我所知,有些摩托罗拉芯片仍使用大端字节序,也许还有一些手机(我不打算将应用程序移植到智能手机上,所以这对我来说无关紧要)。那么,为什么我会重新安排每一个整数,每次短,每一个浮动的字节双,等等,对阅读写作的时候我已经知道,关于小端两种,服务器和客户端运行?

那只是不必要的工作。因此,我的问题是:我可以安全地忽略字节序,而只发送低字节序数据吗?缺点是什么?


4
机器如何知道他们是在接收小端数据,而不是常规/标准的大端数据?
Ixrec '16

2
您需要区分网络协议所需的元数据和有效载荷,有效载荷只是每个未解释的字节,对于您的代码来说,每个字节都是一堆。我希望您不要滚动自己的网络堆栈。因此,我认为问题仅在于有效载荷,对吗?

2
@delnan是的,只谈论有效负载。当然,我仍然会以网络字节顺序与网络堆栈本身对话
tkausl 2016年

3
只是一个侧面的想法:您真的有必要在关注字节顺序的抽象级别上工作吗?可能值得考虑使用协议,在该协议中存在封装所有这些低级“混乱”的适当库。然后,您还可以获得额外的好处,即可以轻松地添加更多客户。
godfatherofpolka

1
@tkausl另外还有两个想法:作为一般规则,IO与计算相比非常慢,因此在较高抽象级别上工作所引起的任何开销很可能都可以忽略不计。由于聪明的资源池和异步处理等原因,有些库甚至可能会超出手动实施的性能。因此,我首先会仔细评估现有解决方案。此外,根据您的描述,我还将花一些精力在可伸缩性而不是性能上,在这里您可能会再次受益于使用更高级别的协议。
godfatherofpolka

Answers:


29

...当我已经知道服务器和客户端都在little endian上运行时,为什么还要重新排列字节?那就是不必要的工作。

仅在可以保证代码始终在低端字节序体系结构上运行时才是不必要的。如果您打算使其使用寿命长,那么值得付出额外的努力来避免在十年后扰乱经过验证的代码,因为某些大端体系结构已成为主流,您会发现它是一个不错的市场你的申请。

有网络标准的字节顺序。它是big-endian,但是没有什么可以说在设计协议时必须遵守它。如果您提前知道大多数运行您的代码的系统将是低位字节序的并且性能至关重要,那么请声明“ tkausl标准字节顺序”并加以使用。在通常需要调用htons()的顺序中,您需要编写一个宏,该宏htots()在小端结构上有条件地编译为空,然后在大端结构上进行重新排列。

维护代码以进行入站和出站转换并不是什么大的工作。如果您有大量消息,请找到一种方法来表达它们并编写程序以生成入站和出站转换。


10
措辞when designing your protocol很重要,因为它还隐含地表示此选项仅在设计新协议时存在,而在实现某些现有协议时不存在。提到需要一个htots(实际上是整个函数系列)时,也很清楚,选择不同的字节顺序并不是使代码更简单的事情,但是可能会使代码更快。
kasperd '16

4
有(无标准,但很常见的这些天)功能htole32()htole16()le16toh()等,可以作为很好的功能。不幸的是,要声明这些文件而包含的文件的标准甚至更低:<endian.h>或者<sys/types.h>取决于平台。
torek '16

这个答案很好,但是我认为在给定情况下性能可能很关键的假设很可能是错误的假设,更多的是基于迷信而非事实。
布朗

1
@DocBrown:我一直想指出,X协议支持选择自己的字节顺序已有30年了,而且由于当时的资源紧张,没有人抱怨这是一个问题。
Blrfl

7

这是您的协议。

您不能安全地忽略它。但是您可以放心地对其进行标记。您控制客户端和服务器。您控制协议。只要您知道双方都同意,就不关心它是大尾数还是小尾数,是否有意义?

这意味着开销。现在,您必须以某种方式标记您的字节序。这样做,我可以阅读任何内容。

如果您不希望有数据开销,并且您的CPU很无聊,正在寻找可以做的事情,请遵循


6

因此,我的问题是:我可以安全地忽略字节序并仅发送低字节序数据吗?

有两种解释:

  • 如果您将应用程序/协议设计为始终发送1个低位字节序,那么您就不会忽略字节序。

  • 如果您将应用程序/协议设计为发送/接收本机字节序,则只要您在具有相同本机字节序的平台上运行应用程序,它们就可以工作。

    那是“安全”的2吗?那是你的判断!但是可以肯定的是,有些通用的硬件平台使用little-endian,big-endian或... bi-endian。

    参考:

缺点是什么?

忽略字节序的明显缺点是,如果您/您的用户需要在具有不同本机字节序的平台之间运行应用程序/协议,那么您就会遇到问题。应用程序将中断,您将需要更改它们以解决问题。并处理版本兼容性问题等。

显然,大多数当前平台本机都是低字节序的,但是1)有些不是,并且2)我们只能猜测将来会发生什么。


1-始终...包括在本地大端的平台上。

2-实际上,“安全”是什么意思?如果您要我们预测硬件平台的未来发展方向...恐怕这是不客观的。


3

字节序不是唯一的考虑因素。有整数的大小,有可能要发送或接收的结构打包,依此类推。

您可以忽略所有这些。没有人可以强迫你。另一方面,安全可靠的方法是记录外部格式,然后编写将正确读取或写入外部格式的代码,无论您的处理器,编程语言和编程语言的实现是什么。

通常它不需要太多代码。但这有一个巨大的好处:读取您的代码的人不会怀疑您一无所知,对交换外部数据一无所知,并且编写通常无法信任的代码。


3

C语言中的标准BSD网络堆栈具有hton/ ntoh功能(network-to-host/ host-to-network),可在网络本地计算机(大端)上扩展为无操作。对于网络本机字节顺序为低端字节序的情况,您需要与之相对应的副本。

这是执行此操作的可靠方法。

这是非常规的,但我认为没有错。联网计算机始终获得字节流,并且它们需要就如何解释这些字节达成协议。这只是其中的一部分。


3

用于在服务器之间传输数据的各种协议使用小尾数:

  1. BSON
  2. 协议缓冲区
  3. Capn Proto

有关各种格式的详细信息,请参见https://en.wikipedia.org/wiki/Comparison_of_data_serialization_formats,其中一些格式为低端数字,某些格式为大端数字。

使用基于小尾数的协议绝对没有错。大字节序机器可以读取小字节序号,就像小字节序机器可以读取大字节序号一样。许多人专门这样做是为了避免在小端序机器上解码大端序号的额外计算成本。

如果您在这些现有协议之一之上构建协议,那么您甚至不必担心这个问题,因为它已经得到了解决。当您决定在big-endian平台上运行代码时,实现这些协议的库将自动确保您正确解码了这些值。


2

大型字节序系统的一个示例是路由器中使用的MIPS。ARM和MIPS都是可字节序转换的,但是MIPS通常是大字节序的,因为它使网络硬件变得更容易(一个词的最重要部分是您首先收到的部分,并且可以在收到其余部分之前做出路由决定。单词,而不必缓冲整个单词)。

因此,这取决于您对“ Linux”的含义,但是,如果您想在较小的系统(例如运行OpenWRT的路由器)上运行服务器应用程序,则可能必须考虑提供大端支持。

像往常一样,简化假设是一个非常明智的优化,直到您遇到不符合假设的情况。只有您能说出,遇到这些问题时放松它们将是多么痛苦。


0

我认为任何答案都不够精确。根据维基百科,字节序是组成一个单词的字节顺序。

让我们取4个字节并将其解释为一个int。一个小的字节序系统将按从右到左的顺序解释字节,在大字节序系统上则反之。显然,重要的是要解释一个int的哪一端。

让我们稍微放大一下可能使用json或xml的现代网络协议。这些格式都不会将int传输为4个字节。他们将以文本形式传输数据,在接收端将其解析为int形式。

因此,最终,使用json或xml时字节序无关紧要。我们仍然需要对tcp标头使用big endian,这就是为什么它被称为网络字节顺序的原因,但是大多数程序员不需要每天与之打乱。

当今最广泛使用的编码是utf-8,它也可以避免字节顺序问题

所以我会说是的。当使用通过utf-8传输的基于文本的格式时,可以忽略字节序。


两次否决,无可奉告。大。
Esben Skov Pedersen

1
我不是拒绝投票的人,但是这个答案似乎正在忽略/忽略一个完全有效的问题。仅仅因为某些协议是基于文本的,并不意味着所有协议都应该是基于文本的。
彼得·格林

2
我赞成这一点,因为它涉及到有效载荷格式与底层协议无关的事实。有些人只是喜欢挖掘虚假的问题。
Zdenek

0

大型字节序系统似乎正在淘汰。许多传统的unix使用big endian,但是多年来一直在下降,以支持x86上的linux。

arm是bi-endian,但似乎很少见到大endian变体。

两种变体中都存在mips。Afaict大端优先变体主要出现在网络应用中(出于历史原因,Internet协议通常使用大端优先)。

ppc传统上是大型字节序,某些部分支持两个字节序,但是IBM似乎现在正在为64位ppc推送小字节序模式(它们最近将ppc64el端口推送到Debian和Ubuntu中)。

sparc通常是大端字节,但似乎又在下降。

如果要实现现有协议,则显然必须遵循其规范。如果您希望IETF祝福您的新协议,那么大字节序可能会更容易,因为那是它们已在现有协议中使用的方法,但是IMO用于新的“未开发地区”协议设计的小字节序是可行的方法。

您可以从一开始就在宏程序中放入宏,而宏程序在小字节序系统上将是无操作的,或者直到/除非您需要移植到大型字节序系统时,您才可以打扰。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.