在C/C++寫網絡程序的時候,往往會遇到字節的網絡順序和主機順序的問題。這是就可能用到htons(), ntohl(), ntohs(),htons()這4個函數。
網絡字節順序與本地字節順序之間的轉換函數:
htonl()--"Host to Network Long"
ntohl()--"Network to Host Long"
htons()--"Host to Network Short"
ntohs()--"Network to Host Short"
之所以需要這些函數是因為計算機數據表示存在兩種字節順序:NBO與HBO
網絡字節順序NBO(Network Byte Order): 按從高到低的順序存儲,在網絡上使用統一的網絡字節順序,可以避免兼容性問題。
主機字節順序(HBO,Host Byte Order): 不同的機器HBO不相同,與CPU設計有關,數據的順序是由cpu決定的,而與操作系統無關。
如 Intel x86結構下, short型數0x1234表示為34 12, int型數0x12345678表示為78 56 34 12 ?
如 IBM power PC結構下, short型數0x1234表示為12 34, int型數0x12345678表示為12 34 56 78
? ?
由于這個原因不同體系結構的機器之間無法通信,所以要轉換成一種約定的數序,也就是網絡字節順序,其實就是如同power pc那樣的順序. 在PC開發中有ntohl和htonl函數可以用來進行網絡字節和主機字節的轉換.
在Linux系統下:htonl(),htons(), ntohl(), ntohs()的頭文件及函數定義: ?
? #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);?
? 在windows系統下:htonl(),htons(), ntohl(), ntohs(), inet_addr()使用說明 ?
? ntohs() ? 簡述:?
? 將一個無符號短整形數從網絡字節順序轉換為主機字節順序。 ?
? #include <winsock.h>?
? u_short PASCAL FAR ntohs( u_short netshort); ??
? netshort:一個以網絡字節順序表達的16位數。 ? 注釋:?
? 本函數將一個16位數由網絡字節順序轉換為主機字節順序。 ??
? 返回值:ntohs()返回一個以主機字節順序表達的數。 ?
?
?ntohl() ? 簡述:?
? 將一個無符號長整形數從網絡字節順序轉換為主機字節順序。 ??
#include <winsock.h>?
?u_long PASCAL FAR ntohl( u_long netlong);
?netlong:一個以網絡字節順序表達的32位數。 ?
?注釋:?
? 本函數將一個32位數由網絡字節順序轉換為主機字節順序。 ??
返回值:?
? ntohl()返回一個以主機字節順序表達的數。 ??
?
htons() ? 簡述:?
? 將主機的無符號短整形數轉換成網絡字節順序。
//將無符號短整型主機字節序轉換為網絡字節序?
? #include <winsock.h>?
? u_short PASCAL FAR htons( u_short hostshort); ??
? hostshort:主機字節順序表達的16位數。 ??
? 注釋:?
? 本函數將一個16位數從主機字節順序轉換成網絡字節順序。?
? 返回值:?
? htons()返回一個網絡字節順序的值。?
? 簡單地說,htons()就是將一個數的高低位互換 ? (如:12 34 --> 34 12) ?
? VB表示:?
? MsgBox Hex(htons(&H1234)) ? 顯示值為 3412 ?
?
? htonl()?
? 簡述:?
? 將主機的無符號長整形數轉換成網絡字節順序。
? ?//將無符號長整型網絡字節序轉換為主機字節序?
? #include <winsock.h>?
? u_long PASCAL FAR htonl( u_long hostlong);?
? hostlong:主機字節順序表達的32位數。?
? 注釋:?
? 本函數將一個32位數從主機字節順序轉換成網絡字節順序。 ??
? 返回值:?
? htonl()返回一個網絡字節順序的值。 ??
??
? inet_addr() ? 簡述:?
? 將一個點間隔地址轉換成一個in_addr。 ??
? #include <winsock.h>?
? unsigned long PASCAL FAR inet_addr( const struct FAR* cp);?
? cp:一個以Internet標準“.”間隔的字符串。
? 例如202.38.214.xx ? 當IP地址為255.255.255.255是被認為無效IP地址。?
? 本函數解釋cp參數中的字符串,這個字符串用Internet的“.”間隔格式表示一個數字的Internet地址。 ??
? 返回值:?
? 一個無符號長整形數,可用作Internet地址。所有Internet地址以網絡字節順序返回(字節從左到右排列)。
?
? inet_ntoa() ? 簡述:?
? 將網絡地址轉換成“.”點隔的字符串格式。 ??
#include <winsock.h>?
char FAR* PASCAL FAR inet_ntoa( struct in_addr in);?
?
in:一個表示Internet主機地址的結構。 ?
?注釋:?
? 本函數將一個用in參數所表示的Internet地址結構轉換成以“.” 間隔的諸如“a.b.c.d”的字符串形式。請注意inet_ntoa()返回的字符串存放在WINDOWS套接口實現所分配的內存中。應用程序不應假設該內存是如何分配的。在同一個線程的下一個WINDOWS套接口調用前,數據將保證是有效。?
? 當IP地址為255.255.255.255是認為有效IP地址。這是與inet_addr()的區別 ??
?返回值:?
? 若無錯誤發生,inet_ntoa()返回一個字符指針。否則的話,返回NULL。其中的數據應在下一個WINDOWS套接口調用前復制出來。 ?
? inet_aton() ? 與inet_ntoa()作用相反。 ??
?
inet_pton() ? 簡述:?
? 本函數將點分十進制轉換為整數 ??
#include <sys/types.h> ??
#include <sys/socket.h> ??
#include <arpa/inet.h>
int inet_pton(int af, const char *src, void *dst);?
? 這個函數轉換字符串到網絡地址,第一個參數af是地址族,轉換后存在dst中 ? inet_pton 是inet_addr的擴展,支持的多地址族有下列: ? af = AF_INET?
? src為指向字符型的地址,即ASCII的地址的首地址(ddd.ddd.ddd.ddd格式的),函數將該地址?
? 轉換為in_addr的結構體,并復制在*dst中 ? af =AF_INET6?
? src為指向IPV6的地址,,函數將該地址轉換為in6_addr的結構體,并復制在*dst中 ? 如果函數出錯將返回一個負值,并將errno設置為EAFNOSUPPORT,如果參數af指定的地址族和src格式不對,函數將返回0。 ??
?
#include <sys/types.h> ??
#include <sys/socket.h> ??
#include <arpa/inet.h>?
const char *inet_ntop(int af, const void *src, char *dst, socklen_t cnt);?
? 這個函數轉換網絡二進制結構到ASCII類型的地址,參數的作用和上面相同,只是多了一個參數socklen_t cnt,他是所?
? 指向緩存區dst的大小,避免溢出,如果緩存區太小無法存儲地址的值,則返回一個空指針,并將errno置為ENOSPC ??
?
atoi()?
? array to integer將字符串轉換為整形數?首先,假設你已經有了一個sockaddr_in結構體ina,你有一個IP地址"132.241.5.10" 要儲存在其中,你就要用到函數inet_addr(),將IP地址從 點數格式轉換成無符號長整型。 ? 使用方法如下:?
? ina.sin_addr.s_addr = inet_addr("132.241.5.10");?
? 注意,inet_addr()返回的地址已經是網絡字節格式,所以你無需再調用 函數htonl()。 ? 我們現在發現上面的代碼片斷不是十分完整的,因為它沒有錯誤檢查。 顯而易見,當inet_addr()發生錯誤時返回-1。記住這些二進制數字?(無符 號數)-1僅僅和IP地址255.255.255.255相符合!這可是廣播地址!大錯特 錯!記住要先進行錯誤檢查。?
? 好了,現在你可以將IP地址轉換成長整型了。有沒有其相反的方法呢? 它可以將一個in_addr結構體輸出成點數格式? 這樣的話,你就要用到函數 inet_ntoa()("ntoa"的含義是"network to ascii"),就像這樣:?
? printf("%s",inet_ntoa(ina.sin_addr));?
? 它將輸出IP地址。需要注意的是inet_ntoa()將結構體in-addr作為一 個參數,不是長整形。同樣需要注意的是它返回的是一個指向一個字符的 指針。它是一個由inet_ntoa()控制的靜態的固定的指針,所以每次調用 inet_ntoa(),它就將覆蓋上次調用時所得的IP地址。例如:?
? char *a1, *a2; ? a1 = inet_ntoa(ina1.sin_addr); /* 這是198.92.129.1 */ ? a2 = inet_ntoa(ina2.sin_addr); /* 這是132.241.5.10 */ ? printf("address 1: %s ",a1); ? printf("address 2: %s ",a2); ? 輸出如下:?
? address 1: 132.241.5.10 ??
address 2: 132.241.5.10?
? 假如你需要保存這個IP地址,使用strcopy()函數來指向你自己的字符指針。 ??