在C/C++寫網絡程式的時候,往往會遇到位元組的網絡順序和主機順序的問題。
這時就可能用到htons(), ntohl(), ntohs(),htons()這4個網絡位元組順序與本地位元組順序之間的轉換函數:
htonl()--"Host to Network Long int" 32Bytes ntohl()--"Network to Host Long int" 32Bytes htons()--"Host to Network Short int" 16Bytes ntohs()--"Network to Host Short int" 16Bytes
之是以需要這些函數是因為計算機資料表示存在兩種位元組順序: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()使用說明
簡述:
将一個無符号短整形數從網絡位元組順序轉換為主機位元組順序。
#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()
将主機的無符号短整形數轉換成網絡位元組順序。//将無符号短整型主機位元組序轉換為網絡位元組序
u_short PASCAL FAR htons( u_short hostshort);
hostshort:主機位元組順序表達的16位數。
本函數将一個16位數從主機位元組順序轉換成網絡位元組順序。
htons()傳回一個網絡位元組順序的值。
簡單地說,htons()就是将一個數的高低位互換
(如:12 34 --> 34 12)
VB表示:
MsgBox Hex(htons(&H1234))
顯示值為 3412
htonl()
簡述:
将主機的無符号長整形數轉換成網絡位元組順序。//将無符号長整型網絡位元組序轉換為主機位元組序
u_long PASCAL FAR htonl( u_long hostlong);
hostlong:主機位元組順序表達的32位數。
本函數将一個32位數從主機位元組順序轉換成網絡位元組順序。
htonl()傳回一個網絡位元組順序的值。
inet_addr()
将一個點間隔位址轉換成一個in_addr。
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()
簡述:
将網絡位址轉換成“.”點隔的字元串格式。
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>
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>
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()函數來指向你自己的字元指針。
***********************************************************************************************************************************
測試代碼如下
#include
int main(int argc, char* argv[])
{
struct in_addr addr1,addr2;
ulong l1,l2;
l1= inet_addr("192.168.0.74");
l2 = inet_addr("211.100.21.179");
memcpy(&addr1, &l1, 4);
memcpy(&addr2, &l2, 4);
printf("%s : %s ", inet_ntoa(addr1), inet_ntoa(addr2)); //注意這一句的運作結果
printf("%s ", inet_ntoa(addr1));
printf("%s ", inet_ntoa(addr2));
return 0;
}
實際運作結果如下:
192.168.0.74 : 192.168.0.74 //從這裡可以看出,printf裡的inet_ntoa隻運作了一次。
192.168.0.74
211.100.21.179
inet_ntoa傳回一個char *,而這個char *的空間是在inet_ntoa裡面靜态配置設定的,是以inet_ntoa後面的調用會覆寫上一次的調用。第一句printf的結果隻能說明在printf裡面的可變參數的求值是從右到左的,僅此而已。