socket编程:字节序


接触到socket编程,就一定会接触字节序转换。

对于字符串来说,是没有字节序的差别的,就像我们写字,内存就像是纸,字符串就从左向右依次写:

内存地址:00000000 00000001 00000002 00000003 ...

内存数据:    'A'            'B'            'C'            'D'

而任何cpu读取的时候,也都是从左向右依次读取。

对于多字节数据(比如short、int、long...),不同字节序是有差别的。

所有x86架构cpu(包括x64)都是用的小端字节序,网络字节序是大端序:

int a = 0x01020304;

内存地址:00000000 00000001 00000002 00000003 ...

大端序a :    0x01        0x02        0x03        0x04            即cpu读出的数据从高向低位写入变量

小端序a :    0x04        0x03        0x02        0x01            即cpu读出的数据从低向高位写入变量

 

如果我们写的程序不进行字节序转换会怎么样呢:

int a = 0x01020304;

在我们x86架构机器的内存里,它是这样写的0x04030201(注意,这是它在内存里的真实写法,当我们的程序以int型读取的时候才会转化成0x01020304),此时进行网络发送,send程序会以字节的方式(可以把它想象成字符串),一字节一字节的发送,到了网络上,它的顺序仍然是0x04030201(此时它的顺序已经错了)。当数据到达对端机器的时候,对端机器也是一字节一字节的收入内存,它的顺序仍然是0x04030201。如果对端仍是x86架构,那么数据读出来的时候它又被转化成了0x01020304,这看起来像是对的。但是如果对端是大端序的架构,那么它的int型数据就变成了0x04030201。

字节序转换:

Linux里提供了现成的函数:htonl, ntohl ...      这是一系列函数,却只提供了2字节和4字节的转换。

判断字节序:

int is_big_endian(void) {
    int test = 0x12345678;
    char *p = (char *)&p;

    if(*p = 0x12)
        return 1;
    else
        return 0;
}

函数虽然简陋,但是已经够用了。

字节序转换宏,顺便将数字转换成数组:

#define rhton16(h, n) {(n)[0]=((unsigned short)(h))>>8; (n)[1]=((unsigned short)(h))<<8>>8;}
#define rhton32(h, n) {(n)[0]=((unsigned int)(h))>>24; (n)[1]=((unsigned int)(h))<<8>>24; (n)[2]=((unsigned int)(h))<<16>>24; (n)[3]=((unsigned int)(h))<<24>>24;}
#define rhton64(h, n) {(n)[0]=((unsigned long)(h))>>56; (n)[1]=((unsigned long)(h))<<8>>56; (n)[2]=((unsigned long)(h))<<16>>56; (n)[3]=((unsigned long)(h))<<24>>56; (n)[4]=((unsigned long)(h))<<32>>56; (n)[5]=((unsigned long)(h))<<40>>56; (n)[6]=((unsigned long)(h))<<48>>56; (n)[7]=((unsigned long)(h))<<56>>56;}

数组转换成数字:

#define rntoh16(n) (((unsigned short)((n)[1])) | ((unsigned short)((n)[0])<<8))
#define rntoh32(n) (((unsigned int)((n)[3])) | ((unsigned int)((n)[2])<<8) | ((unsigned int)((n)[1])<<16) | ((unsigned int)((n)[0])<<24))
#define rntoh64(n) (((unsigned long)((n)[7])) | ((unsigned long)((n)[6])<<8) | ((unsigned long)((n)[5])<<16) | ((unsigned long)((n)[4])<<24) | ((unsigned long)((n)[3])<<32) | ((unsigned long)((n)[2])<<40) | ((unsigned long)((n)[1])<<48) | ((unsigned long)((n)[0])<<56))

本文永久更新链接地址

相关内容