一些关于网络字节序的知识

写在开头: 以下内容为在其他作者博文中看到的,转自:链接: link.

在程序中发数据包时,应把主机字节需转换为网络字节序,收数据包时,应把网络字节序转主机字节序。

什么是网络字节序

网络字节顺序是TCP/IP中规定好的一种数据表示格式,它与具体的CPU类型、操作系统等无关,从而可以保证数据在不同主机之间传输时能够被正确解释。网络字节顺序采用big endian排序方式
为了进行转换 bsd socket提供了转换的函数 有下面四个

  • htons 把unsigned short类型从主机序转换到网络序
  • htonl 把unsigned long类型从主机序转换到网络序
  • ntohs 把unsigned short类型从网络序转换到主机序
  • ntohl 把unsigned long类型从网络序转换到主机序
    在使用little endian的系统中 这些函数会把字节序进行转换
    在使用big endian类型的系统中 这些函数会定义成空宏
    同样 在网络程序开发时 或是跨平台开发时 也应该注意保证只用一种字节序 不然两方的解释不一样就会产生bug.

字节序的问题涉及硬件架构,目前主要是Motorola的PowerPC系列CPU和Intel的x86系列CPU。PowerPC系列采用big endian方式存储数据,而x86系列则采用little endian方式存储数据。那么究竟什么是big endian,什么又是little endian呢?

大端和小端

为方便理解,摘了INTER手册中的一张图。

字节顺序是指占内存多于一个字节类型的数据在内存中的存放顺序,通常有小端、大端两种字节顺序。小端字节序指低字节数据存放在内存低地址处,高字节数据存放在内存高地址处;大端字节序是高字节数据存放在低地址处,低字节数据存放在高地址处大端才是在内存中反过来放的)。

基于IAX86平台的PC机是小端字节序的,而有的嵌入式平台则是大端字节序的。因而对WORD/DWORD/QWORD等多于1字节类型的数据,在这些嵌入式平台上应该变换其存储顺序。通常我们认为,在空中传输的字节的顺序即网络字节序(什么是网络字节序)为标准顺序,考虑到与协议的一致以及与同类其它平台产品的互通,在程序中发数据包时,将主机字节序转换为网络字节序,收数据包处将网络字节序转换为主机字节序。

用文字说明可能比较抽象,下面用图像加以说明。比如数字0x12345678在两种不同字节序CPU中的存储顺序如下所示:

小端字节序指低字节数据存放在内存低地址处,高字节数据存放在内存高地址处;大端字节序是高字节数据存放在低地址处,低字节数据存放在高地址处。

对于0x12345678,

Little endian(小端字节),X86系列:高地址<------->低:存储数据0x12 0x34 0x56 0x78

Big endian(大端字节),PowerPC系列: 高地址<------->低:存储数据0x78 0x56 0x34 0x12

为什么要注意字节序的问题呢?当然,如果你写的程序只在单机环境下面运行,并且不和别人的程序打交道,那么你完全可以忽略字节序的存在。但是,如果你的程序要跟别人的程序产生交互呢?C/C++语言编写的程序里数据存储顺序是跟编译平台所在的CPU相关的,而JAVA编写的程序则唯一采用big endian方式来存储数据。试想,如果你用C/C++语言在x86平台下编写的程序跟别人的JAVA程序互通时会产生什么结果?就拿上面的0x12345678来说,你的C/C++程序(假设CPU平台是小端,Intel的)传递给别人的一个数据,将指向0x12345678的指针(对C来说,指针变量指向的内存地址是最低字节地址,即0x78的地址)传给了JAVA程序,由于JAVA采取big endian方式存储数据,很自然的它会将你的数据翻译为0x78563412。因此,在你的C程序传给JAVA程序之前有必要进行字节序的转换工作。

所有网络协议也都是采用big endian的方式来传输数据的所以有时我们也会把big endian方式称之为网络字节序。当两台采用不同字节序的主机通信时,在发送数据之前都必须经过字节序的转换成为网络字节序后再进行传输。

判断小端还是大端规则的方法

int x = 1; 
if(*(char *)&x == 1)    //取x指针强制转换为char*类型再取值,此时取到的值是int最低字节值 
    printf("little-endian/n"); //说明低字节0x01存放在32位地址的低地址
else 
    printf("big-endian/n"); 

另外补充:

1.BIG-ENDIAN、LITTLE-ENDIAN是跟CPU有关的,每一种CPU不是BIG-ENDIAN就是LITTLE-ENDIAN。IA架构的CPU中是Little-Endian,而PowerPC 、SPARC和Motorola处理器是BIG-ENDIAN。这其实就是所谓的主机字节序。而网络字节序是指数据在网络上传输时是大头还是小头的,在Internet的网络字节序是BIG-ENDIAN(大端是高字节先传,小端是低字节先传)。所谓的JAVA字节序指的是在JAVA虚拟机中多字节类型数据的存放顺序,JAVA字节序也是BIG-ENDIAN。

2.所以在用C/C++写通信程序时,在发送数据前务必用htonl和htons去把整型和短整型的数据进行从主机字节序到网络字节序的转换,而接收数据后对于整型和短整型数据则必须调用ntohl和ntohs实现从网络字节序到主机字节序的转换如果通信的一方是JAVA程序、一方是C/C++程序时,则需要在C/C++一侧使用以上几个方法进行字节序的转换,而JAVA一侧,则不需要做任何处理,因为JAVA字节序与网络字节序都是BIG-ENDIAN,只要C/C++一侧能正确进行转换即可(发送前从主机序到网络序,接收时反变换)。如果通信的双方都是JAVA,则根本不用考虑字节序的问题了

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值