1、大端、小端字節序
考慮一個16位整數,它由2個字節組成。內存中存儲這兩個字節有兩種方法:一種是將低序字節存儲在起始地址,這稱為小端(little-endian)字節序;另一種方法是將高序字節存儲在起始地址,這稱為大端(big-endian)字節序。如下所示:
術語“大端”和“小端”表示多個字節值的哪一端(小端或大端)存儲在該值的起始地址。
遺憾的是,這兩種字節序之間沒有標准可循,兩種格式都有系統使用。比如,Inter x86、ARM核采用的是小端模式,Power PC、MIPS UNIX和HP-PA UNIX采用大端模式。
2、網絡字節序和主機字節序
網絡字節序
網絡字節序是TCP/IP中規定好的一種數據表示格式,它與具體的CPU類型、操作系統等無關,從而可以保證數據在不同主機之間傳輸時能夠被正確解釋。網絡字節序采用big endian排序方式。
主機字節序
不同的機器主機字節序不相同,與CPU設計有關,數據的順序是由cpu決定的,而與操作系統無關。我們把某個給定系統所用的字節序稱為主機字節序(host byte order)。比如x86系列CPU都是little-endian的字節序。
由於這個原因不同體系結構的機器之間無法通信,所以要轉換成一種約定的數序,也就是網絡字節順序。
網絡字節序與主機字節序之間的轉換函數:htons(), ntohs(), htons(),htonl(),位於頭文件<netinet/in.h>,htons和ntohs完成16位無符號數的相互轉換,htonl和ntohl完成32位無符號數的相互轉換。
在使用little endian的系統中,這些函數會把字節序進行轉換;
在使用big endian類型的系統中,這些函數會定義成空宏;
在網絡程序開發時 或是跨平台開發時,也應該注意保證只用一種字節序,不然兩方的解釋不一樣就會產生bug。
3、IP地址的三種表示格式及在開發中的應用
1)點分十進制表示格式
2)網絡字節序格式
3)主機字節序格式
用IP地址127.0.0.1為例:
第一步 127 . 0 . 0 . 1 把IP地址每一部分轉換為8位的二進制數。
第二步 01111111 00000000 00000000 00000001 = 2130706433 (主機字節序)
然后把上面的四部分二進制數從右往左按部分重新排列,那就變為:
第三步 00000001 00000000 00000000 01111111 = 16777343 (網絡字節序)
eg:
struct sockaddr_in addrSrv;
// addrSrv.sin_addr.S_un.S_addr=htonl(2130706433);
addrSrv.sin_addr.S_un.S_addr = inet_addr(
"127.0.0.1"
);
addrSrv.sin_family=AF_INET;
addrSrv.sin_port=htons(6000);
4、inet_aton()、inet_addr()和inet_aton()函數
頭文件: <arpa/inet.h>
1)int inet_aton(const char *strptr, struct in_addr *addrptr);
將strptr所指C字符串轉換成一個32位的網絡字節序二進制值,並通過指針addrptr來存儲。若成功則返回1,否則返回0。
2)in_addr_t inet_addr(const char *strptr)
若字符串有效,則返回值為32位的網絡字節序二進制值,否則為INADDR_NONE。
該函數存在一個問題,所有2^32個可能的二進制值都是有效的IP地址(0.0.0.0---255.255.255.255),但是當出錯時該函數返回INADDR_NONE常值(通常是一個32位均為1的值)。這意味着點分十進制數串255.255.255.255不能由該函數處理,因為它的二進制值用來指示該函數失敗。所以該函數已經被廢棄,應該盡量用inet_aton()函數,或者將要說到的inet_pton()函數。
3)char *inet_ntoa(struct in_addr inaddr);
將一個32位的網絡字節序二進制值IPv4地址轉換成相應的點分十進制數串。該函數以一個結構而不是以指向該結構的一個指針作為其參數。
返回:指向一個點分十進制數串的指針
5、inet_pton()和inet_ntop()函數
這兩個函數是隨着IPv6出現的新函數,對於IPv4地址和IPv6地址都適用。函數名中p和n分別代表表達(presentation)和數值(numeric)。
頭文件: <arpa/inet.h>
總結這幾個轉換函數: