网络字节序

网络字节序

什么是大端和小端?

  • 大端(高端字节序,网络字节序):低位地址存放高位数据,高位地址存放低位数据
  • 小端(低端字节序):低位地址存放低位数据,高位地址存放高位数据

什么时候使用大端和小端?

  • 大端和小端只是对数据类型长度是两个及以上的,如int,short,对于单字节没限制,在网络中经常需要考虑大端和小端的是IP端口

大小端转换函数

网络传输用的是大端法

如果机器用的是小端法,则需要进行大小端的转换

下面4个函数就是进行大小端转换的函数

1
2
3
4
5
6
#include <arpa/inet.h>

uint32_t htonl(uint32_t hostlong);
uint16_t htons(uint16_t hostshort);
uint32_t ntohl(uint32_t netlong);
uint16_t ntohs(uint16_t netshort);

函数名的h表示主机 host,n表示网络network,s表示short,l表示long

上述的几个函数,如果本来不需要转换,函数内部就不会做转换

IP 地址转换函数

点分十进制IP转网络IP

int inet_pton(int af, const char *src, void *dst);

  • 函数说明

    • 将字符串形式的点分十进制 IP 转换为大端模式的网络 IP(整型 4字节数)
  • p:表示点分十进制的字符串形式

  • to:到

  • n:表示network 网络

  • 参数说明

    • af:AF_INET(IPV4),AF_INET6(IPV6)
    • src:字符串形式的点分十进制的IP 地址
    • dst:存放转换后的变量的地址
  • 例如:inet_pton(AF_INET,”127.0.0.1”,&serv.sin_addr.s_addr);

网络IP转点分十进制IP

const char* inet_ntop(int af, const void *src, char *dst, socklen_t size);

  • 函数说明

    • 网络 IP 转换为字符串形式的点分十进制的IP
  • 参数说明

    • af:AF_INET(IPV4),AF_INET6(IPV6)
    • src:网络的整形的IP 地址
    • dst:转换后的IP 地址保存的位置,一般为字符串数组
    • size:dst 的长度
  • 返回值

    • 成功:返回指向 dst 的指针

    • 失败:返回 NULL,并设置 errno

例如:

IP 地址为 010aa8c0,转换为点分十进制的格式

01 ➡️ 1, 0a ➡️ 10, a8 ➡️ 168, c0 ➡️ 192

由于网络中的 IP 地址是高端模式,所以转换为点分十进制后应该为:192.168.10.1

查看当前主机的字节序

那么如何查看本机的字节序用的是大端还是小端?

可以编写下面这个程序简单的测出当前机器的字节序顺序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#include <stdio.h>
#include <stdlib.h>

union{
short s;
char c[sizeof(short)];
}un2;

union{
int s;
char c[sizeof(int)];
}un4;

int main(){
printf("[%d],[%d]\n",sizeof(short),sizeof(int));
un2.s = 0x0102; // 258 - 0000 0001 0000 0010
// 如果c[0]输出的是2,说明是低(小)端,如果输出的是1,说明是高(大)端
printf("[%d],[%d],[%d]\n",un2.c[0],un2.c[1],un2.s);

un4.i = 0x01020304;
// 同理,如果c[0]输出的是4,说明是低(小)端,如果输出的是1,说明是高(大)端
printf("[%d],[%d],[%d],[%d],[%d]\n",un4.c[0],un4.c[1],un4.c[2],un4.c[3],un4.i);

return 0;
}

输出结果

QQ_1729936426559

可以看出我这台机器是小端模式

  • 低位 02 放在低位地址 un2.c[0] 中,高位01放在高位地址un2.c[1]中。
  • 低位 04 放在低位地址 un4.c[0] 中,高位01放在高位地址un4.c[3]中。