- 字節順序定義
字節順序是指佔內存多於一個字節類型的數據在內存中的存放順序,通常有小端、大端兩種字節順序。小端字節序指低字節數據存放在內存低地址處,高字節數據存放在內存高地址處;大端字節序是高字節數據存放在低地址處,低字節數據存放在高地址處。(一個字節的數據當然就無需談順序的問題)。
在大部分的開發中我們不需要考慮字節序的問題。唯有在跨平臺以及網絡程序應用中字節序纔是一個應該被考慮的問題。
- 網絡應用的字節序
網絡字節序是TCP/IP規定好的一種數據表示格式,它與具體的CPU類型、操作系統無關,從而可以保證數據在不同主機之間傳輸時能被正確解釋。網絡字節順序採用big endian排序方式。
在網絡編程時,並不是什麼時候都要考慮字節序問題。那麼什麼時候需要考慮呢?
Intel CPU使用的都是little endian。
實際上如果是應用層的數據,即對TCP/IP來說是透明的數據,不用考慮字節序的問題。因爲接收端收到的順序是和發送端一致的。
基於X86平臺的PC機是小端字節序的,而有的嵌入式平臺則是大端字節序的。因而對int、uint16、uint32等多於1字節類型的數據,在這些嵌入式平臺上應該變換其存儲順序。通常我們認爲,網絡字節序爲標準順序,考慮到與協議的一致以及與同類其它平臺產品的互通,在程序中發數據包時,將主機字節序轉換爲網絡字節序,收數據包處將網絡字節序轉換爲主機字節序。
下面以一個實際的例子來說明主機字節序和網絡字節序的區別:
unsigned short port = 0x0018;
SOCKADDR_IN sodkaddr;
LPVOID ja= &sodkaddr;
sodkaddr.sin_port = port;
sodkaddr.sin_port = htons(port);
能夠看到程序在執行完:
sodkaddr.sin_port = port;
時,內存中的數據是如下圖形式:
0x0018FB98 cc cc 18 00 cc cc
而網絡字節序是大端形式,即高位存儲在內存低地址,則在創建端口時其讀取的數據爲 : 0x1800,這與我們預期的肯定不一致,因此如果不使用相應的轉換函數先行轉換的話,後期會發生無法預料的錯誤。
當我們繼續往下執行完這句時:
sodkaddr.sin_port = htons(port);
內存中的數據如下圖所示:
0x0018FB98 cc cc 00 18 cc
此時若創建端口,則其讀取的數據爲:0x0018,與我們預期的設計一致。
- 字節序轉換函數
htons 把 unsigned short 類型從主機序轉換到網絡序
htonl 把 unsigned long 類型從主機序轉換到網絡序
ntohs 把 unsigned short 類型從網絡序轉換到主機序
ntohl 把 unsigned long 類型從網絡序轉換到主機序
上面這幾個函數可以按照這樣的方式記憶,例如:htons函數,則代表 host to network,s 代表 unsigned short
char FAR * inet_ntoa( struct in_addr in);
將一個IP轉換成一個互聯網標準點分格式的字符串。
in_addr_t inet_addr(const char *cp);
將一個點分十進制的IP轉換成一個長整數型數(u_long類型)。返回值即爲網絡字節順序,可以直接作爲internet 地址
SOCKADDR_IN addrSrv;
addrSrv.sin_addr.S_un.S_addr=inet_addr("127.0.0.1");
char recvBuf[100];
char tempBuf[100];
sprintf(tempBuf,"%s say: %s",inet_ntoa(addrSrv.sin_addr),recvBuf);
inet_ntoa(addrSrv.sin_addr)將sin_addr儲存的IP(數值)轉換成字符串形式(127.0.0.1)