http://blog.csdn.net/luotuo44/article/details/19234553
先說說為什么會有大小端字節序的問題。現在PC機的一個整型變量一般是32位的,由4個字節組成。在計算機內存中,每個字節都是有地址的。也就是說一個整型的4個字節的地址是不同的,有高低地址之分。對於一個整數,如632523,其對應的二進制位1001 10100110 11001011。需要3個字節才能放得下。這時就存在一個問題,對於低8位11001011是存放在整型的那4個字節的低地址位還是高地址位。
如果將低8位存放在4個字節中的低地址位,稱為小端字節序,如果將低8位存放在高地址位,則為大端字節序。助記:沿着內存的增長方向,先存低8位是的小端;先存高8位的是大端。大小端字節序是由CPU決定的[1][2][3]。
雖然不同的CPU廠商可以隨意選擇一種字節序作為自己的內存字節序,但是網絡字節序就不能任由各個CPU選擇,網絡字節序被規定為大端字節序。
一般來說,主機要先把端口號從主機字節序轉換到網絡字節序。有下面的函數可以相互轉換。
- #include<netinet/in.h>
- unsigned long int htonl(unsigned long int hostlong);
- unsigned short int htons(unsigned short int hostshort);
- unsigned long int ntohl(unsigned long int netlong);
- unsigned short int ntohs(unsigned short int netshort);
其中,htonl 表示”host to network long”。
有了這些轉換函數,用戶就不需要知道所在的OS/CPU用的什么字節序。反正這些函數會被我們想要的值轉換成網絡字節序的值。
除了這4個函數外,在頭文件endian.h中,還定義了很多主機字節序和大小端字節序相互轉換的函數。
從這里可以看到,下面函數是在glibc 2.9及之后的版本才支持。可以用$ldd --version命令 查看glibc的版本。
其中,be是表示大端,le是表示小端。
上圖中的那些函數(其實那些是宏定義),用來配置端口號是沒有用的,因為已經有htons函數了。但在解決TCP粘包問題中,這些函數就可以派上用場了。
解決TCP粘包問題的一個方法是,在每條消息的頭部添加一個長度字段。每一個主機在發送消息前,都把長度轉換成大端字節序存放(轉換成小端字節序也行,只要CS兩端統一即可)。然后發送消息。對端在收到消息的長度字段后,就將其從大端字節序轉換成主機字節序。
這里存在一個問題,怎么將怎么將收到的字節流轉換成大端字節序的整型變量。答案是用memcpy函數。在發送端將整型變量變成字節流也是用這個函數。
如下面代碼所示:
- //發送端
- int len = htobe32(a);
- char ch[10];
- memcpy(ch, &len, sizeof(len) );
- //接收端
- int len;
- char* message;
- memcpy(&len, message, sizeof(len) );
- a = be32toh(len);
CDataStream里的實現是通過賦值運算實現的:
void writeint32(int32 iValue)
{
assert((current_ + sizeof(int32)) <= (buffer_ + size_));
if((current_ + sizeof(int32)) <= (buffer_ + size_))
{
*((int32*)current_) = iValue;
current_ +=sizeof(int32);
}
else
good_bit_ = false;
}
int readint32()
{
assert((current_ + sizeof(int32)) <= (buffer_ + size_));
if((current_ + sizeof(int32)) <= (buffer_ + size_))
{
current_ +=sizeof(int32);
return *((int32*)(current_-sizeof(int32)));
}
good_bit_ = false;
return 0;
}
不過它沒有處理網絡字節序和主機字節序
參考:
[1] http://en.wikipedia.org/wiki/Endianness
[2] http://stackoverflow.com/questions/9237317/what-makes-a-system-little-endian-or-big-endian
[3] http://superuser.com/questions/308274/what-determines-endianness