【Linux】网络字节序

网络字节序:

我们知道,内存中的多字节数据相对于内存地址有大端和小端之分,磁盘文件中的多字节数据相对于文件中的偏移也有大端与小端之分,网络数据同样有大端小端之分。我们在讲述之前,先弄清楚如何定义网络数据流的地址。(总概)

  • 发送主机(源主机)通常将发送缓冲区中的数据按内存地址从低到高的顺序发出
  • 接收主机把从网络上接到的字节依次保存在接收缓冲区中,也是按内存地址从低到高的顺序保存
  • 因此网络数据流的地址这样规定:先发出的数据是低地址数据,后发出的数据是高地址
  • TCP/IP协议规定,网络数据流采用大端字节序,即低地址存高字节
  • 不管这台主机是大端字节序还是小端字节序,都会按照这个TCP/IP规定的网络字节序(转化出大端字节序)来发送/接收数据
  • 如果当前发送的主机是小端,则需要将数据转成大端;否则,直接发送

我们来更加详细的讲述一下字节序

字节序:cpu从内存中对数据进行存取的顺序
主机字节序的分类:大端字节序/小端字节序
大端字节序:低地址存高位
小端字节序:低地址存低位

栗子:
int a = 0x01 02 03 04
那么a的二进制位数是:00000001 00000010 00000011 00000100
uchar* b =(uchar*)&a ;
如果b[0] = 1 , b[1] = 2 , b[2] = 3 , b[3] = 4 的话,说明低地址存的是高位,是大端字节序;
如果b[0] = 4 , b[1] = 3 , b[2] = 2 , b[3] = 1 的话,说明低地址存的是低位,是小端字节序;

那么如何确定一个主机字节序是大端的还是小端的?

typedef union
{
	int a ;
	uchar b;
}U;
U un;
int un.a = 1;

if(un.b == 1)        // 小端字节序
if(un.b == 0)        // 大端字节序

我们用联合体的思路判断,是大端还是小端字节序

决定一个主机字节序是大端还是小端的关键在于cpu架构
例如:
X86 – 小端字节序
MIPS – 大端字节序

主机字节序对网络通信的影响?

int a = 0x01 02 03 04
如果源主机字节序和目的主机字节序相同时,那么01020304 -> 01020304,数据a传送过去后,数据不会发生变化。
如果两台主机的字节序不一样的话,假设源主机字节序为小端字节序,目的主机的字节序为大端字节序。那么数据a传送过去后,目的主机的字节序是大端的,所以低地址存高位,所以a传过去就成了0x04 03 02 01。
所以不同主机的字节序的两台主机进行通信的时候有可能会造成数据二义。
因此做出规定,在网络通信中统一使用大端字节序进行通信。

主机字节序会对哪些数据造成影响?

对存储数据大于一个字节类型的数据:short/int/float/double 等等,它们在网络传输中都需要转换字节序。而char arr[64]就是不会受影响的,因为它是按字节进行存储的。
转换字节序,都用网络字节序。程序的可移植性会提高。

字节序转换的库函数

为了使网络程序具有可移植性,使用同样的代码在大端和小端计算机上编译后都能正常的运行,可以调用一下库函数做网络字节序和主机字节序的转换。

#include <arpa/inet.h>

unit32_t htonl(uint32_t hostlong);
unit16_t htons(uint16_t hostshort);
unit32_t ntohl(uint32_t netlong);
unit16_t ntohl(uint16_t netshort);
  • h表示host,n表示network,l表示32位长整数,s表示16位短整数。
  • 例如htonl表示将32位的长整数从主机字节序转换为网络字节序,例如将IP地址转换后准备发送。
  • 如果主机是小端字节序,这些函数将参数做相应的大小端转换然后返回;
  • 如果主机是大端字节序,这些 函数不做转换,将参数原封不动地返回。
发布了55 篇原创文章 · 获赞 12 · 访问量 5269

猜你喜欢

转载自blog.csdn.net/weixin_43939593/article/details/103212944