网络字节与大小端

字节序分为大端字节序和小端字节序

现代PC大多采用小端字节序,所以小端字节序又被称为主机字节序。
大端字节序也称为网络字节序。
大端模式是指高字节数据存放在低地址处,低字节数据放在高地址处。
小端模式是指低字节数据存放在低地址处,高字节数据放在高地址处。
通过对大小端的存储原理分析可发现,对于 char 型数据,由于其只占一个字节,所以不存在这个问题,这也是一般情况下把数据缓冲区定义成 char 类型 的原因之一。对于 IP 地址、端口号等非 char 型数据,必须在数据发送到网络上之前将其转换成大端模式,在接收到数据之后再将其转换成符合接收端主机的存储模式。

大小端转换

#if defined(BIG_ENDIAN) && !defined(LITTLE_ENDIAN)
 
   #define htons(A) (A)
   #define htonl(A) (A)
   #define ntohs(A) (A)
   #define ntohl(A) (A)
 
#elif defined(LITTLE_ENDIAN) && !defined(BIG_ENDIAN)
 
   #define htons(A) ((((uint16_t)(A) & 0xff00) >> 8 ) | \\
                      (((uint16_t)(A) & 0x00ff) << 8 ))
   #define htonl(A) ((((uint32_t)(A) & 0xff000000) >> 24) | \\
                      (((uint32_t)(A) & 0x00ff0000) >> 8 ) | \\
                      (((uint32_t)(A) & 0x0000ff00) << 8 ) | \\
                      (((uint32_t)(A) & 0x000000ff) << 24))
   #define ntohs     htons
   #define ntohl     htohl
 
#else
 
   #error Either BIG_ENDIAN or LITTLE_ENDIAN must be #defined, but not both.
 
#endif

Linux 系统为大小端模式的转换提供了 4 个函数,输入 man byteorder 命令可得函数原型:

#include <arpa/inet.h> 
 
uint32_t htonl(uint32_t hostlong); 
 
uint16_t htons(uint16_t hostshort); 
 
uint32_t ntohl(uint32_t netlong); 
 
uint16_t ntohs(uint16_t netshort);

htonl 表示 host to network long ,用于将主机 unsigned int 型数据转换成网络字节顺序;
htons 表示 host to network short ,用于将主机 unsigned short 型数据转换成网络字节顺序;
ntohl、ntohs 的功能分别与 htonl、htons 相反。

判断大小端

#include <iostream>
using namespace std;

union myunion
{
    int i;
    char j;
};

int isLittleEndian_1(void)
{
    myunion test;
    test.i = 1;
    return (test.i == test.j);
}

int isLittleEndian_2(void)
{
    int i =1;
    if (*((char *)&i) == 1) {
        return 1;
    }
    return 0;
}
int isLittleEndian_3(void)
{
    unsigned int i =0X1234;
    if (*((char *)&i) == 0X34) {
        return 1;
    }
    return 0;
}

int main(int argc, char const *argv[])
{
    /* 系统大小端测试1 */
    if (isLittleEndian_1)
    {
        cout<<"当前系统是小端模式"<<endl;
    }else {
        cout<<"当前系统是大端模式"<<endl;
    }  
    /* 系统大小端测试2 */
    if (isLittleEndian_2)
    {
        cout<<"当前系统是小端模式"<<endl;
    }else {
        cout<<"当前系统是大端模式"<<endl;
    } 
    /* 系统大小端测试3 */
    if (isLittleEndian_3)
    {
        cout<<"当前系统是小端模式"<<endl;
    }else {
        cout<<"当前系统是大端模式"<<endl;
    }     
    return 0;
}

结果:
xzj@xzj-VirtualBox:~/development_test/process/big_little_Endian$ ./run
当前系统是小端模式
当前系统是小端模式
当前系统是小端模式

详解大端模式和小端模式

网络数据的大小端问题

posted @ 2019-08-05 12:14  独孤剑—宇枫  阅读(551)  评论(0编辑  收藏  举报