文章

字节序

字节序

字节序,又称端序或尾序,指的是多字节数据在内存中的存放顺序。

大端和小端

计算机有两种储存数据的方式:大端字节序(Big Endian)和小端字节序(Little Endian)。

大端模式:是指数据的高字节保存在内存的低地址中,低字节保存在内存的高地址端。

小端模式:是指数据的高字节保存在内存的高地址中,低字节保存在内存的低地址端。

以一个两字节short型变量0x0102的存储举例:

大端字节序:高位字节在前,低位字节在后,0102,从左往右看着更习惯。
小端字节序:低位字节在前,高位字节在后,0201,也存在这种存储顺序。

以0x12345678这个数字为例,它的大端模式和小端模式分别如下:

大端字节序符合阅读习惯;小端字节序计算机处理效率高

网络序和主机序

网络字节序:TCP/IP各层协议将字节序定义为Big Endian,即大端模式,TCP/IP协议中使用的字节序是大端序。

主机字节序:整数在内存中存储的顺序,目前以Little Endian,即小端模式,比较普遍(不同的CPU有不同的字节序)。

主机序转换到网络序

  1. htons函数

    函数功能:将主机无符号短整形数转换成网络。举例说明如果把htons(16)输出你会看到得到的结果是4096,为什么呢?因为16的十六进制是0X0010,而4096的十六进制是0X1000。

    uint16_t htons(uint16_t hostshort)

    返回值:返回一个网络字节顺序的值

    参数说明:其中hostlong是主机字节顺序表达的16位数,htons中的h表示host意思是主机地址,to表示to意思是去往,转换为的意思,n表示net意思是网络,s表示signed long意思是无符号的短整型。

  2. htonl函数

    函数功能:将一个32位数从主机字节顺序转换成网络字节顺序。

    uint32_t htonl(uint32_t hostlong)

    返回值:返回一个网络字节顺序的值

    参数说明:其中hostlong是主机字节顺序表达的32位数,htons中的h表示host意思是主机地址,to表示to意思是去往,转换为的意思,n表示net意思是网络,l 是 unsigned long表示32位长整数

网络序转换到主机序

  1. ntohs函数

    函数功能:将一个无符号短整型数从网络字节顺序转换成主机字节顺序。这个函数与htons原理相同,不过是htos是主机序到网络序,而ntohs是网络序到主机序。

    uint16_t ntohs(uint16_t netshort)

    返回值:返回一个主机字节顺序表达的数

    参数说明:其中netshort一个以网络字节顺序表达的16位数,ntohs中的h表示host意思是主机地址,to表示to意思是去往,n表示net意思是网络,s表示signed long意思是无符号的短整型(32位的系统是2字节)。

  2. ntohl函数

    函数功能:将一个无符号长整型从网络字节顺序转换成主机字节顺序。这个函数与htonl原理相同,不过是htol是主机序到网络序,而ntohl是网络序到主机序。

    uint32_t ntohl函数(uint32_t netlong)

    返回值:返回一个主机字节顺序表达的数。

    参数说明:其中netlong一个以网络字节顺序表达的32位数,ntohs中的h表示host意思是主机地址,to表示to意思是去往,n表示net意思是网络,s表示signed long意思是无符号的短整型(32位的系统是2字节)。

ip地址转化为用于网络传输的二进制数值

  1. inet_aton函数

    头文件:<arpa/inet.h>

    函数功能:将一个字符串表示的点分十进制IP地址IP转换为网络字节序存储在addr中

    int inet_aton(const char *IP, struct in_addr *addr)

    返回值:失败返回0,成功返回1。

    参数说明: IP : 输入的点分十进制IP地址 addr : 将IP转换为网络字节序(大端存储)后并保存在addr中

  2. inet_addr函数

    in_addr_t inet_addr(const char *cp);

    功能:转换网络主机地址(如192.168.1.10)网络字节序二进制值

    参数:十进制的ip地址,如192.168.69.1

    返回值:错误时返回-1,成功返回二进制形式的IP地址

将网络传输的二进制数值转化为成点分十进制的ip地址

  1. inet_ntoa函数 头文件:<arpa/inet.h>

    函数功能:将一个网络字节序的IP地址(也就是结构体in_addr类型变量)转化为点分十进制的IP地址(字符串)。

    char* inet_ntoa(struct in_addr in)

    返回值:该函数的返回值是一个字符串,这个字符串是点分十进制的IP地址。

新型网路地址转化函数inet_pton和inet_ntop

p和n分别代表表达(presentation)和数值(numeric)。地址的表达格式通常是ASCII字符串,数值格式则是存放到套接字地址结构的二进制值。

功能上跟inet_atoninet_ntoa类似

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include <arpe/inet.h>

/*  将缓冲区中从 CP 开始的互联网号码的演示格式转换为二进制网络格式,
	并将结果存储在转换为二进制网络格式,并将结果存储为
	接口类型 AF 的结果存储在从 BUF 开始的缓冲区中  */
extern int inet_pton (int __af, const char *__restrict __cp,
		      void *__restrict __buf) __THROW;

// 将点分十进制ip地址转化为用于网络传输的数值格式
// 成功返回1,若输入不是有效表达式则返回0,错误返回-1

/* 以二进制网络格式转换接口的互联网地址
   将从 CP 开始的缓冲区中的 AF 类型转换为表示形式,
   并将结果放入长度为 LEN(从 BUF 开始)的缓冲区中。
   将结果放入从 BUF 开始长度为 LEN 的缓冲区中.  */
extern const char *inet_ntop (int __af, const void *__restrict __cp,
			      char *__restrict __buf, socklen_t __len)
     __THROW;

// 将数值格式转化为点分十进制的ip地址格式
// 成功返回指向结构的指针,错误返回NULL

程序解析:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include <stdio.h>
#include <stdlib.h>
#include <arpa/inet.h>

int main() {
    char IP[] = "192.168.69.1";
    struct in_addr address;
    int number = inet_aton(IP, &address);
    if (number == 0) {
        printf("Invalid IP address\n");
        return -1;
    }

    printf("IP address in number format: %u\n", address.s_addr);
    printf("IP address in string format: %s\n", inet_ntoa(address));

    return 0;
}

运行结果:

1
2
IP address in number format: 21342400
IP address in string format: 192.168.69.1

转换过程:

192.168.69.1转成二进制为 1100 0000 1010 1000 0100 0101 0000 0001

转成小端序为0000 0001 0100 0101 1010 1000 1100 0000,十进制为‭21342400‬

本文由作者按照 CC BY 4.0 进行授权