【网络篇】第四篇——网络字节序

简介: 【网络篇】第四篇——网络字节序

网络字节序和本机转换


计算机在存储数据时是有大小端的概念的:

  • 大端模式: 数据的高字节内容保存在内存的低地址处,数据的低字节内容保存在内存的高地址处。
  • 小端模式: 数据的高字节内容保存在内存的高地址处,数据的低字节内容保存在内存的低地址处。

如果编写的程序只在本地机器上运行,那么是不需要考虑大小端问题的,因为同一台机器上的数据采用的存储方式都是一样的,要么采用的都是大端存储模式,要么采用的都是小端存储模式。但如果涉及网络通信,那就必须考虑大小端的问题,否则对端主机识别出来的数据可能与发送端想要发送的数据是不一致的。


例如,现在两台主机之间在进行网络通信,其中发送端是小端机,而接收端是大端机。发送端将发送缓冲区中的数据按内存地址从低到高的顺序发出后,接收端从网络中获取数据依次保存在接收缓冲区时,也是按内存地址从低到高的顺序保存的。

image.png

但由于发送端和接收端采用的分别是小端存储和大端存储,此时对于内存地址从低到高为44332211的序列,发送端按小端的方式识别出来是0x11223344,而接收端按大端的方式识别出来是0x44332211,此时接收端识别到的数据与发送端原本想要发送的数据就不一样了,这就是由于大小端的偏差导致数据识别出现了错误。

由于我们不能保证通信双方存储数据的方式是一样的,因此网络当中传输的数据必须考虑大小端问题。因此TCP/IP协议规定,网络数据流采用大端字节序,即低地址高字节。无论是大端机还是小端机,都必须按照TCP/IP协议规定的网络字节序来发送和接收数据。

  • 如果发送端是小端,需要先将数据转成大端,然后再发送到网络当中。
  • 如果发送端是大端,则可以直接进行发送。
  • 如果接收端是小端,需要先将接收到数据转成大端后再进行数据识别。
  • 如果接收端是大端,则可以直接进行数据识别。

在这个例子中,由于发送端是小端机,因此在发送数据前需要先将数据转成大端,然后再发送到网络当中,而由于接收端是大端机,因此接收端接收到数据后可以直接进行数据识别,此时接收端识别出来的数据就与发送端原本想要发送的数据相同了。

image.png

需要注意的是,所有的大小端的转化工作是由操作系统来完成的,因为该操作属于通信细节,不过也有部分的信息需要我们自行进行处理,比如端口号和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;
}

为什么网络字节序采用的是大端?而不是小端?

网络字节序采用的是大端,而主机字节序一般采用的是小端,那为什么网络字节序不采用小端呢?如果网络字节序采用小端的话,发送端和接收端在发生和接收数据时就不用进行大小端的转换了。

该问题有很多不同说法,下面列举了两种说法:

  • 说法一: TCP在Unix时代就有了,以前Unix机器都是大端机,因此网络字节序也就采用的是大端,但之后人们发现用小端能简化硬件设计,所以现在主流的都是小端机,但协议已经不好改了。
  • 说法二: 大端序更符合现代人的读写习惯。

字节序转换函数


为使网络程序具有可移植性,使同样的C代码在大端和小端计算机上编译后都能正常运行,系统提供了四个函数,可以通过调用以下库函数实现网络字节序和主机字节序之间的转换。

 #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----long。
htons()--"Host to Network Short"
htonl()--"Host to Network Long"
ntohs()--"Network to Host Short"
ntohl()--"Network to Host Long"

函数名当中的h表示host,n表示network,l表示32位长整数,s表示16位短整数。

例如htonl表示将32位长整数从主机字节序转换为网络字节序。

如果主机是小端字节序,则这些函数将参数做相应的大小端转换然后返回。

如果主机是大端字节序,则这些函数不做任何转换,将参数原封不动地返回。

相关文章
|
3月前
|
Linux C语言 Windows
C语言 网络编程(六)字节序
本文介绍了在不同操作系统中查看IP地址和网络状态的方法,包括Windows下的`ipconfig`与Linux下的`ifconfig`命令,并详细解析了网络字节序转换函数。通过`inet_aton()`和`inet_addr()`可将IP字符串转换为网络字节序,而`inet_ntoa()`则实现相反操作。此外,还提供了`htons()`与`ntohs()`等函数进行主机字节序与网络字节序之间的转换,并附带示例代码帮助理解。
|
7月前
网络字节序和主机序(大端和小端)详细解释--通过封装IP协议头去理解网络字节序
网络字节序和主机序(大端和小端)详细解释--通过封装IP协议头去理解网络字节序
652 1
|
7月前
了解网络字节序
了解网络字节序
58 1
|
7月前
|
存储 网络协议
网络编程之字节序
网络编程之字节序
49 0
|
7月前
网络编程之 字节序和深入理解bind()函数
在上一篇博客里,大家也许会对htons()感到疑惑吧,其实就是字节序的转换,所以这篇博客我们就来详细的解释一下什么是字节序。
104 0
|
存储 网络协议 Unix
socket | 网络套接字、网络字节序、sockaddr结构
socket | 网络套接字、网络字节序、sockaddr结构
128 0
|
存储 网络协议 编译器
字节序,主机字节序与网络字节序
是指多字节数据在计算机内存中存储或者网络传输时各字节的存储顺序。在计算机中是以字节为单位,每个地址对应一个字节,一个字节8bit。在C中,除了8bit的char以外,还有16bit的short,32位的int,64位long,当然具体要由编译器决定,可以通过sizeof来获取不同类型在内存中占用的字节数。在计算机系统中,当物理单位的长度大于1个字节时(所以char数据就不用区分字节序),就要区分字节顺序。常见的字节顺序有两种:大端和小端,当然还有其他字节顺序,但不常见,例如Middle Endian,通俗的讲,字节序就是cpu对内存中进行存储的顺序(以字节为单位进行存取)
229 0
|
存储 网络协议 芯片
清晰讲解LSB、MSB和大小端模式及网络字节序
清晰讲解LSB、MSB和大小端模式及网络字节序
1992 0
|
网络协议 网络架构
计算机网络:IP、端口、网络通信协议、TCP/IP五层模型、字节序
计算机网络:IP、端口、网络通信协议、TCP/IP五层模型、字节序
144 0
计算机网络:IP、端口、网络通信协议、TCP/IP五层模型、字节序