什么时候是htonl(x)!= ntohl(x)? (或者在同一台计算机上进行网络字节顺序转换时是否相同?)

时间:2012-07-23 17:45:05

标签: sockets endianness

关于htonlntohl。这两行代码中的任何一行何时评估为false。

 htonl(x) == ntohl(x);

 htonl(ntohl(x)) == htonl(htonl(x));

换句话说,这两个操作何时不等同于在同一台机器上?我能想到的唯一场景是一台机器,它不能用于表示整数的2的补码。

原因主要是历史,编码清晰度还是其他原因?

现在是否存在任何现代架构或环境,在这些架构或环境中,在同一台机器上进行网络字节顺序转换是不同方向的相同代码?

3 个答案:

答案 0 :(得分:6)

我找不到Posix规范的原始草稿,但最近的一个found online有一个提示。

  

网络字节顺序可能不便于处理实际值。   为此,将值存储为普通值更为明智   整数。这称为“主机字节顺序”。在主机字节顺序中:

The most significant bit might not be stored in the first byte in address order.

**Bits might not be allocated to bytes in any obvious order at all.**
     

存储在uint8_t对象中的8位值不会   需要转换为主机字节顺序或从主机字节顺序转换,因为它们具有相同   表示。可以使用。转换16位和32位值   htonl(),htons(),ntohl()和ntohs()函数。

有趣的是,以下陈述是在

的讨论下作出的
  

POSIX标准明确要求8位字符和二进制补码算法。

这基本上排除了我对1的补码机器实现的想法。

但是“任何明显的命令”声明基本上都表明posix委员会至少认为运行posix / unix运行于大或小端以外的东西的可能性。因此,不能排除声明htonl和ntohl作为不同的实现。

所以简短的回答是“htonl和ntohl是相同的实现,但是两个不同函数的接口是为了将来与未知的兼容。”

答案 1 :(得分:5)

多年前我为UNIVAC 1100系列大型机写了一个TCP / IP堆栈。这是一个36位,可字寻址的计算机体系结构,具有1的补码算法。

当这台机器进行通信I / O时,来自外部世界的8位字节将被放入每个9位四分之一字的低8位。所以在这个系统上,ntohl()会将每个四分之一字中的8位压缩到字的低32位(前4位为零),因此你可以对它进行算术运算。

同样,htonl()将取一个字中的低32位并撤消此操作,将每个8位数量放入每个9位四分之一字的低8位。

因此,为了回答原始问题,这台计算机体系结构上的ntohl()和htonl()操作彼此非常不同。

例如:

COMP*                                 . COMPRESS A WORD
          LSSL      A0,36             . CLEAR OUT A0
          LSSL      A1,1              . THROW AWAY TOP BIT
          LDSL      A0,8              . GET 8 GOOD ONE'S
          LSSL      A1,1              .
          LDSL      A0,8              .
          LSSL      A1,1              .
          LDSL      A0,8              .
          LSSL      A1,1              .
          LDSL      A0,8              .
          J         0,X9              .
.
DCOMP*                                . DECOMPRESS A WORD
          LSSL      A0,36             . CLEAR A0
          LSSL      A1,4              . THROW OUT NOISE
          LDSL      A0,8              . MOVE 8 GOOD BITS
          LSSL      A0,1              . ADD 1 NOISE BIT
          LDSL      A0,8              . MOVE 8 GOOD BITS
          LSSL      A0,1              . ADD 1 NOISE BIT
          LDSL      A0,8              . MOVE 8 GOOD BITS
          LSSL      A0,1              . ADD 1 NOISE BIT
          LDSL      A0,8              . MOVE 8 GOOD BITS
          J         0,X9              .

COMP相当于ntohl()和DCOMP到htonl()。对于那些不熟悉UNIVAC 1100汇编代码的人:-) LSSL是“Left Single Shift Logical”的一个寄存器,由多个位置组成。 LDSL是指定计数的“左双移逻辑”对的一对寄存器。因此,LDSL A0,8将连接的A0,A1寄存器移位8位,将A1的高8位移入A0的低8位。

此代码是1981年为UNIVAC 1108编写的。几年后,当我们有一个1100/90并且它开发了一个C编译器时,我开始了一个BSD NET / 2 TCP / IP实现的端口并实现了ntohl( )和htonl()以类似的方式。可悲的是,我从未完成那项工作..

如果你想知道为什么某些互联网RFC使用术语“八位字节”,因为当天的某些计算机(如PDP-10,Univacs等)的“字节”不是8位。 “八位字节”专门定义为8位字节。

答案 2 :(得分:-2)

并非所有机器都具有相同的字节顺序,这些方法会处理这些问题。假设'网络秩序'是大端。如果您的计算机运行大端架构并运行ntohl,则输出将与输入相同(因为字节序与网络相同)。如果您的机器是一个小端架构,ntohl会将数据从大端转换为小端。关于htonl也是如此(必要时将主机数据转换为网络字节顺序)。要回答您的问题,当您在具有不同字节顺序的两台计算机之间传输数据时,这两项操作并不等效。