网络字节序与主机字节序的转换函数实践
在Linux网络编程中,经常碰到网络字节序与主机字节序的相互转换。说到网络字节序与主机字节序需要清晰了解以下几个概念。
主机字节序
字节序,是字节在电脑中存放时的序列与输入(输出)时的序列是先到的在前还是后到的在前。比如一个int32_t类型的数值占用4个字节,这4个字节在内存中的排列顺序就是字节序。字节序可以分为两种:
(1)小端字节序(Little endinan),数值低位存储在内存的低地址,高位存储在内存的高地址;
(2)大端字节序(Big endian),数值高位存储在内存的低地址,低位存储在内存的高地址。
以32位位宽数值0x12345678为例,小端字节序与大端字节序具体的存储区别如下所示:
小端模式优点 :
强制转换数据不需要调整字节内容,1、2、4字节的存储方式一样。
大端模式优点 :
符号位的判定固定为第一个字节,容易判断正负。
网络字节序
网络数据流也有大小端之分。
网络数据流的地址规定:先发出的数据是低地址,后发出的数据是高地址。发送主机通常将发送缓冲区中的数据按内存地址从低到高的顺序发出,为了不使数据流乱序,接收主机也会把从网络上接收的数据按内存地址从低到高的顺序保存在接收缓冲区中。TCP/IP协议规定:网络数据流应采用大端字节序,即低地址高字节。
大小端转换
常用的转换函数:
函数原型 | 函数说明 |
---|---|
uint16_t htons(uint16_t hostshort); | 将 16 位的主机字节序转换为网络字节序 |
uint32_t htonl(uint32_t hostlong); | 将 32 位的主机字节序转换为网络字节序 |
uint16_t ntohs(uint16_t netshort); | 将 16 位的网络字节序转换为主机字节序 |
uint32_t ntohl(uint32_t netlong); | 将 32 位的网络字节序转换为主机字节序 |
其中
- uint16_t:无符号的 16 位整数(等同于 unsigned short)
- uint32_t:无符号的 32 位整数(等同于 unsigned int)
点击这里,通过以下代码可以查看自己电脑是大端还是小端
#include<stdio.h>
int main(int argc, char** argv)
{
union {
short s;
char c[sizeof(short)];
} un;
un.s = 0x0102;
if (sizeof(short) == 2) {
if (un.c[0] == 1 && un.c[1] == 2)
printf("big-endian\n");
else if (un.c[0] == 2 && un.c[1] == 1)
printf("little-endian\n");
else
printf("unknown\n");
}
return 0;
}