计算机网络 —— 网络字节序

计算机网络 —— 网络字节序网络字节序

大家好,欢迎来到IT知识分享网。

网络字节序

1、网络字节序 (Network Byte Order)和本机转换

1、大端、小端字节序

“大端” 和” 小端” 表示多字节值的哪一端存储在该值的起始地址处;小端存储在起始地址处,即是小端字节序;大端存储在起始地址处,即是大端字节序。

  • ① 大端字节序(Big Endian): 最高有效位存于最低内存地址处,最低有效位存于最高内存地址处;
  • ② 小端字节序(Little Endian):最高有效位存于最高内存地址,最低有效位存于最低内存地址处。

“高位数据”和”低位数据”

通常指的是数据在存储或传输时的位置或顺序。在处理二进制数据、字节序、位操作以及数据存储时非常常见,用于描述数据的物理存储方式或传输顺序。

  • 高位数据:指的是数据的高阶位或高字节,通常存储在数据块的起始位置或最高有效位(Most Significant Bit,MSB)。在多字节数据中,高位数据对应于数据的较高位部分。
  • 低位数据:指的是数据的低阶位或低字节,通常存储在数据块的末尾或最低有效位(Least Significant Bit,LSB)。在多字节数据中,低位数据对应于数据的较低位部分。

如下图:当以不同的存储方式,存储数据为 0x 时:

视角 1
在这里插入图片描述

视角 2

在这里插入图片描述
视角 3
在这里插入图片描述

网络字节序:大端字节序

UDP/TCP/IP 协议规定:把接收到的第一个字节当作高位字节看待, 这就要求发送端发送的第一个字节是高位字节;而在发送端发送数据时,发送的第一个字节是该数值在内存中的起始地址处对应的那个字节。换句话说,该数值在内存中的起始地址处对应的那个字节就是要发送的第一个高位字节。

所以,网络字节序就是大端字节序, 有些系统的本机字节序是小端字节序,有些则是大端字节序,为了保证传送顺序的一致性, 网际协议使用大端字节序来传送数据

如何验证自己的机器采用了哪种字节顺序:

/* 确定你的电脑是大端字节序还是小端字节序 */ #include <stdio.h> int check1() { 
    int i = 1; //1在内存中的表示: 0x00000001 char *pi = (char *)&i; //将int型的地址强制转换为char型 return *pi == 0; //如果读取到的第一个字节为1,则为小端法,为0,则为大端法 } int main() { 
    if (check1() == 1) printf("big\n"); else printf("little\n"); return 0; } 

第二种方法,用联合结构解决,其本质差异不大

/* 确定你的电脑是大端字节序还是小端字节序 */ #include <stdio.h> int check2() { 
    union test { 
    char ch; int i; }test0; test0.i = 1; return test0.ch == 0; } int main() { 
    if (check1() == 1) printf("big\n"); else printf("little\n"); return 0; } 

对本例中的联合结构,对它求 sizeof(test0),会发现它的大小为 4,取了 int 的大小。

关于 union,它里边的变量共用一块存储空间,但是它的大小并不总是其中最大的变量所占的空间,还需要考虑对齐!

比如:

union test1 { 
    char[5]; int i; } 

它的大小就是 8 了!

2、字节序转换函数

/* 字节序转换函数 */ #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----longhtons()--"Host to Network Short" htonl()--"Host to Network Long" ntohs()--"Network to Host Short" ntohl()--"Network to Host Long" 

为什么在数据结构 struct sockaddr_in 中, sin_addr 和 sin_port 需要转换为网络字节顺序,而 sin_family 不需要呢?

答案是: sin_addrsin_port 分别封装在包的 IPUDP 层。因此,它们必须是网络字节顺序。但是 sin_family 域只是被内核 (kernel) 使用来决定在数据结构中包含什么类型的地址,所以它必须是本机字节顺序。同时, sin_family 没有发送到网络上,它们可以是本机字节顺序

IP 地址如何处理:地址转换函数

IP 地址的三种表示格式及在开发中的应用

  • 1)点分十进制表示格式
  • 2)网络字节序格式
  • 3)主机字节序格式

用IP地址127.0.0.1为例:

 第一步 127 . 0 . 0 . 1 把 IP 地址每一部分转换为 8位的二进制数。 第二步 0 00000000 00000000 00000001 =  (主机字节序)    然后把上面的四部分二进制数从右往左按部分重新排列,那就变为: 第三步 00000001 00000000 00000000 0 =  (网络字节序) 

1、函数inet_addr(),将 IP 地址从 点数格式转换成无符号长整型。使用方法如下:

函数原型

in_addr_t inet_addr(const char *cp); 

转换网络主机地址(点分十进制)为网络字节序二进制值,

  • cp 代表点分十进制的 IP 地址,如 1.2.3.4
  • 如果参数 char *cp 无效则返回 – 1 (INADDR_NONE),
  • 此函数有个缺点:在处理地址为 255.255.255.255 时也返回 – 1,虽然它是一个有效地址,但 inet_addr () 无法处理这个地址。

使用

ina.sin_addr.s_addr = inet_addr("132.241.5.10"); 

现在可以将 IP 地址转换成长整型了。有没有其相反的方法可以将一个 in_addr 结构体输出成点数格式?

2、你就要用到函数 inet_ntoa()(“ntoa”的含义是”network to ascii”),就像这样:
函数原型

char* inet_ntoa(struct in_addr in); 

参数:

  • in 代码 in_addr 的结构体,其结构体如下:
struct in_addr { 
    union { 
    struct { 
    UCHAR s_b1,s_b2,s_b3,s_b4; } S_un_b; struct { 
    USHORT s_w1,s_w2; } S_un_w; ULONG S_addr; } S_un; }; 

使用

SOCKADDR_IN sock; sock.sin_family = AF_INET; //将字符串转换为 in_addr 类型 sock.sin_addr.S_un.S_addr = inet_addr("192.168.1.111"); sock.sin_port = htons(5000); //将 in_addr 类型转换为字符串 printf("inet_ntoa ip = %s\n",inet_ntoa(sock.sin_addr)); 结果输出: inet_ntoa ip = 192.168.1.111 
char *a1, *a2; …… a1 = inet_ntoa(ina1.sin_addr); /* 这是198.92.129.1 */ a2 = inet_ntoa(ina2.sin_addr); /* 这是132.241.5.10 */ printf("address 1: %s\n",a1); printf("address 2: %s\n",a2); 输出如下: address 1: 132.241.5.10 address 2: 132.241.5.10 

Via:

计算机网络——网络字节序(大端字节序(Big Endian)\小端字节序(Little Endian)

计算机网络 —— 网络字节序

免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://haidsoft.com/131002.html

(0)
上一篇 2025-08-11 14:10
下一篇 2025-08-11 14:15

相关推荐

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注微信