网络字节序

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

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

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

如下图:当以不同的存储方式,存储数据为0x12345678时:
在这里插入图片描述
网络字节序:大端字节序
网络上传输的数据都是字节流,对于一个多字节数值,在进行网络传输的时候,先传递哪个字节?也就是说,当接收端收到第一个字节的时候,它将这个字节作为高位字节还是低位字节处理,是一个比较有意义的问题:

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");
		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");
		printf("little\n");
	return 0;

因为联合结构中的变量共用一块存储空间,所以ch和i拥有同一个地址:
在这里插入图片描述

对本例中的联合结构,我们对它求sizeof(test0),会发现它的大小为4,取了int 的大小。
关于union,我们说了,它里边的变量共用一块存储空间,但是它的大小并不总是其中最大的变量所占的空间,还需要考虑对齐!
union test1 {
char[5];
int i;
它的大小就是 8 了!

2、字节序转换函数

字节序转换函数

 #include <arpa/inet.h>
//将主机字节序转换为网络字节序
 unit32_t htonl (unit32_t hostlong);
 unit16_t htons (unit16_t hostshort);
 //将网络字节序转换为主机字节序
 unit32_t ntohl (unit32_t netlong);
 unit16_t ntohs (unit16_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位的二进制数。
  第二步 01111111     00000000     00000000     00000001      =   2130706433   (主机字节序)
  然后把上面的四部分二进制数从右往左按部分重新排列,那就变为:
  第三步 00000001     00000000     00000000    01111111        =   16777343        (网络字节序)

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

注意:
inet_ntoa()将结构体in_addr作为一个参数,不是长整形。同样需要注意的是它返回的是一个指向一个字符的 指针。它是一个由inet_ntoa()控制的静态的固定的指针,所以每次调用 inet_ntoa(),它就将覆盖上次调用时所得的IP地址。例如:

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
                    网络字节序 网络字节序1、网络字节序 (Network Byte Order)和本机转换2、字节序转换函数网络字节序1、网络字节序 (Network Byte Order)和本机转换1、大端、小端字节序“大端”和”小端”表示多字节值的哪一端存储在该值的起始地址处;小端存储在起始地址处,即是小端字节序;大端存储在起始地址处,即是大端字节序;具体的说:①大端字节序(Big Endian):最高有效位存于最低内存地址处,最低有效位存于最高内存处;②小端字节序(Little Endian):最高有效位
  字节序是由于不同主处理器(CPU)和操作系统(OS)对多字节的变量在内存中存放顺序的不同而产生的。
  字节序的分类?一般分为两类:
  ①小端字节序Little Endian,LE):变量的内存地址起始地址存放低字节,高字节顺序存放
  ②大端字节序Big Endian, BE):变量的内存地址起始地址存放高字节,低字节顺序存放
				
大端字节序小端字节序1.什么是大小端字节序2.验证大小端字节序 1.什么是大小端字节序 计算机硬件有两种储存数据的方式:大端字节序(MSB)和 小端字节序(LSB)。 小端字节序(LSB) 将这样的数据存储在计算机中,地址从地位到高位应该是:78 56 34 12 int a=0x12345678 一共四个字节的地址,假设从0x1001 ~ 0x1004;那么,对于小端字节序来说系统是这样存储的: 由图可以看出,小端字节序的存储规则是:数据的低位存储在地址低位,数据的高位存储在地址高位 大端字节序
一、什么是字节序? 多字节数据存储在存储器中的顺序就叫做字节序字节序又分为俩种,一种叫做小端字节序;另外一种叫做大端字节序。 二、大端字节序Big Endian)& 小端字节序Little Endian大端字节序:在大端字节序的机器中,首先会存储多字节数据类型的二进制表示的第一个字节; 小端字节序:在小端字节序的机器中,首先会存储多字节数据类型的二进制表示的最后一个字节; 我们用...
1. 字节序 字节序即字节的存储顺序,如果数据都是单字节的,那怎么存储无所谓了,但是对于多字节数据,比如int,double等,就要考虑存储的顺序了。字节序是硬件层面的东西,通常只和你使用的处理器架构有关,而和编程语言无关。字节序分为大端序和小端序。 大端序:数据的高位字节存放在地址的低端 低位字节存放在地址高端。 小端序:数据的高位字节存放在地址的高端 低位字节存放在地址低端。 0x1234567的大端字节序小端字节序的写法如下图。 可见,大端模式和字符串的存储模式类似...
小端在计算机业界,endian表示数据在存储器中的存放顺序。“endian”一词来源于乔纳森·斯威夫特的小说格列佛游记。 小说中,小人国为水煮蛋该从大的一端(Big-End)剥开还是小的一端(Little-End)剥开而争论,争论的双方分别被称为“大端派”和“小端派”。 看到没有,仅仅是剥鸡蛋就能产生这么大的分歧,“大端”和“小端”有这么重要嘛! 什么是字节序 字节(Byte)是存储数据的...
(0)背景: 网络上的数据流是字节流,对于一个多字节数值,在进行网络传输的时候,先传递哪个字节?也就是说,当接收端收到第一个字节的时候,它是将这个字节作为高位还是低位来处理呢?  (1)网络字节序定义: 收到的第一个字节被当作高位看待,这就要求发送端发送的第一个字节应当是高位。 (2)网络字节序大端序列: 在发送端发送数据时,发送的第一个字节是该数字在内存中起始地址对应
一、为什么会出现大小端模式? 不同的cpu采用的大小端模式不一致。X86是小端模式。而KEIL C51则为大端模式。很多的ARM,DSP都为小端模式。有些ARM处理器还可以由硬件来选择是大端模式还是小端模式。 二、大小端模式的不同带来的问题是什么?如何解决? 如果存在数据网络传输,如果大小端模式不一致,如果不经过转换,必然会导致数据不致,出现错误。 解决方法:统一将网络上传输的
网络字节序是一种规定好的字节序,用于在网络中传输数据。它采用大端字节序Big-Endian),即高位字节存储在低地址,低位字节存储在高地址。 而主机字节序是指计算机处理器自身的字节序,根据不同的体系结构,可能采用大端字节序小端字节序Little-Endian)。 在网络通信中,需要将主机字节序转换为网络字节序才能正确传输数据。这可以通过一些特定的函数或库来完成,例如htonl(主机到网络长整型)、htons(主机到网络短整型)、ntohl(网络到主机长整型)和ntohs(网络到主机短整型)等。这些函数可以确保在不同主机之间正确地处理字节序,以实现正确的数据传输。