Linux原始套接字 - ip头中的字节序

时间:2015-01-23 07:18:57

标签: c linux sockets endianness

我想确认ip标头中任何大于一个字节的值(short,int ..或者它们的替代int16_t ..)应该使用ntohs / ntohl等转换为big endian以通​​过线路发送。< / p>

当使用普通套接字或使用其他技术时,内核管理了这个吗?

由于某些功能,例如使用ioctl获取接口的ip地址,似乎已经将数据转换为sockaddr_in *时的大端方式,因此非常混乱。它输出我的地址,如36.2.168.192(与printf的%d),但ifreq输出它像192.168.2.36

int addr = ((struct sockaddr_in *)(&ifr.ifr_addr))->sin_addr.s_addr;
printf("%d %d %d %d ", (addr >> 24) & 255 , (addr >> 16) & 255,(addr >> 8) & 255, (addr) & 255);

以相反的顺序给我我的IP地址

而使用

for (int _x = 0; x < 14; ++_x) {
        printf("%d ", ifr.ifr_ifru.ifru_addr.sa_data[_x] );
}

将以正确的顺序(192.168.2.36)给我一些零地址,然后是零。 哇..我迷路了。

如果你问我,那就相当丛林。

问题

什么转换成大端,什么不转?

1 个答案:

答案 0 :(得分:3)

最好不要将它视为big-endian或little-endian,而是主机订单(可能是其中之一)和网络订单(big-endian)。您是正确的,在IP标准中,每个字段都按网络顺序排列。您应该使用ntohsntohl函数将网络转换为主机顺序,并使用htonshtonl函数将主机转换为网络顺序。这样你的代码也可以在big-endian机器上编译。

IP地址通常以网络顺序存储在内部,在这种情况下,可以使用inet_ptoninet_ntop将其转换为表示格式。因此,除非您手动应用网络掩码等,否则通常不需要使用这些地址的存储格式。如果您这样做,八位字节(您和我的字节)以自然顺序存储,即111.222。 33.44以111,222,33和44的顺序存储。如果你考虑一下,这是一个大端命令。