IP地址格式
阿新 • • 發佈:2019-01-10
使用TCP/IP協議進行網路應用開發的朋友首先要面對的就是對IP地址資訊的處理。IP地址其實有三種不同的表示格式,關於這一點,如果你還不知道,亦或對相關的知識還有所迷惑,本文對你將會有很大的幫助。
Ascii(網路點分字串)-
網路地址(32位無符號整形,網路位元組序,大頭)
主機地址 (主機位元組序)
IP地址是IP網路中資料傳輸的依據,它標識了IP網路中的一個連線,一臺主機可以有多個IP地址,IP分組中的IP地址在網路傳輸中將保持不變。下面具體介紹IP地址的三種不同表示格式。
一、點分10進製表示格式
這是我們最常見的表示格式,比如某機的IP地址可能為“202.101.105.66”。事實上,對於Ipv4(IP版本)來說,IP地址是由一個32位的二進位制數所構成,但這樣一串數字序列無疑是十分冗長並且
難以閱讀和記憶的。為了方便人們的記憶和使用,就將這串數字序列分成4組,每組8位,並改為用 10進位制數進行表示,最後用小原點隔開,於是就演變成了“點分10進製表示格式”。
來看看剛才那個IP地址的具體轉化過程:
IP地址:11001010011001010110100101000010
分成4組後:11001010 01100101 01101001 01000010
十進位制表示:202 101 105 66 www.2cto.com
點分表示:202.101.105.66
二、網路位元組順序格式(NBO,Network Byte Order)
下面我們來談談網路位元組順序格式,它和我們後面將要介紹的主機位元組順序格式一樣,都只在進行網路開發中才會遇到。因此,在下面的介紹中,我假設讀者對Socket 程式設計知識有一定的基礎。
在網路傳輸中,TCP/IP協議在儲存IP地址這個32位二進位制數時,協議規定採用在低位儲存地址中包含資料的高位位元組的儲存順序(大頭),這種順序格式就被稱為網路位元組順序格式。在實際網路傳輸時,資料按照每32位二進位制數為一組進行傳輸,由於儲存順序的影響,實際的位元組傳輸順序是由高位位元組到低位位元組的傳輸順序。 為了使通訊的雙方都能夠理解資料分組所攜帶的源地址、目的地址以及分組的長度等二進位制資訊,無論是主機還是路由器,在傳送每一個分組以前,都必須將二進位制資訊轉換為TCP/IP標準的網路位元組順序格式。網路位元組順序格式的地址不受主機、路由器型別的影響,它的表示是唯一的。
在Socket程式設計開發中,通過函式inet_addr和inet_ntoa可以實現點分字串與網路位元組順序格式IP地址之間的轉換。 inet_addr函式原型如下: unsigned long inet_addr(const char FAR * cp) 函式中的引數cp指向網路中標準的點分地址字串,其中每個以點分開的數字不可以大於255,這些數字可以是十進位制、八進位制、十六進位制或者混合使用。如 “10.23.2.3”、“012.003.002.024”、“0xa.0x3.0x14.0x2”、“10.003.2.0x12”。 我們在前面的socket程式設計提到server端的程式碼,連線本地埠: /* File Name: client.c */ #include<stdio.h> #include<stdlib.h> #include<string.h> #include<errno.h> #include<sys/types.h> #include<sys/socket.h> #include<netinet/in.h> #define MAXLINE 4096 int main(int argc, char** argv) { int sockfd, n,rec_len; char recvline[4096], sendline[4096]; char buf[MAXLINE]; www.2cto.com struct sockaddr_in servaddr; if( (sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0){ printf("create socket error: %s(errno: %d)\n", strerror(errno),errno); exit(0); } memset(&servaddr, 0, sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_port = htons(8000); //可以使用:inet_pton(AF_INET, "127.0.0.1", servaddr.sin_addr); servaddr.sin_addr.s_addr = inet_addr("127.0.0.1");//將字串形式的IP地址轉換為按網路位元組順序的整形值 connect(sockfd, (struct sockaddr*)&servaddr, sizeof(servaddr)) ; printf("send msg to server: \n"); fgets(sendline, 4096, stdin); send(sockfd, sendline, strlen(sendline)); irec_len = recv(sockfd, buf, MAXLINE,0); buf[rec_len] = '\0'; printf("Received : %s ",buf); close(sockfd); www.2cto.com } 三、主機位元組順序格式(HBO,Host Byte Order) 主機位元組順序格式顧名思義,其IP地址的格式是和具體主機或者路由器相關的。對於不同的主機,在進行IP地址的儲存時有不同的格式,比如對於 Motorola 68k系列主機,其HBO與NBO是相同的。而對於Intel x86系列,HBO與NBO則正好相反。 在Socket程式設計中,有四個函式來完成主機位元組順序格式和網路位元組順序格式之間的轉換,它們是:htonl、htons、ntohl、和ntohs。 htons和ntohs完成16位無符號數的相互轉換,htonl和ntohl完成32位無符號數的相互轉換。 在實際應用中我們常見到將埠號轉換的例子(如上例)。這是因為,如果使用者輸入一個數字,而且將指定使用這一數字作為埠號,應用程式則必須在使用它建立地址以前,把它從主機位元組順序轉換成網路位元組順序(使用htons()函式),以遵守TCP/IP協議規定的儲存標準。相應地,如果應用程式希望顯示包含於某一地址中的埠號(例如從getpeername()函式中返回的),這一埠號就必須在被顯示前從網路順序轉換到主機順序(使用ntohs()函式)。 那麼,對於IP地址,主機位元組順序格式的轉換又有哪些應用呢? 應用一,如果想知道從202.156.2.23到202.156.9.65這兩個IP之間到底有多少個主機地址怎麼辦?這時就可以將兩個IP地址轉換為主機位元組順序的格式然後相減來得到,具體的實現如下: int GetIPCount(char * ip1,char * ip2) { long pp;; long ss;; pp = ntohl(inet_addr(ip1));; ss = ntohl(inet_addr(ip2));; return(ss - pp + 1);; } 應用二,如果對一個網段進行掃描,比如,當前正在掃描202.156.23.255,怎麼讓程式知道下一個應掃的IP是202.156.24.0?這時可以將當前IP轉換成主機位元組順序格式並加1後,在轉換回網路格式 即可,具體實現如下: char * GetNextIp(char * m_curip) { struct sockaddr_in in;; long pp;; www.2cto.com char * re;; pp = ntohl(inet_addr(m_curip));; pp = pp + 1;; in.sin_addr.s_addr = htonl(pp);; re = inet_ntoa(in.sin_addr);; return (re);; } 總結 本文介紹了IP地址的三種不同表示格式,包括各種格式產生的原因、具體含義以及在Socket程式設計開發中的一些應用。在實際應用中,必須遵循應用時所應採用的格式標準,同時還應靈活運用格式間的相互轉換以及計算技巧。
在Socket程式設計開發中,通過函式inet_addr和inet_ntoa可以實現點分字串與網路位元組順序格式IP地址之間的轉換。 inet_addr函式原型如下: unsigned long inet_addr(const char FAR * cp) 函式中的引數cp指向網路中標準的點分地址字串,其中每個以點分開的數字不可以大於255,這些數字可以是十進位制、八進位制、十六進位制或者混合使用。如 “10.23.2.3”、“012.003.002.024”、“0xa.0x3.0x14.0x2”、“10.003.2.0x12”。 我們在前面的socket程式設計提到server端的程式碼,連線本地埠: /* File Name: client.c */ #include<stdio.h> #include<stdlib.h> #include<string.h> #include<errno.h> #include<sys/types.h> #include<sys/socket.h> #include<netinet/in.h> #define MAXLINE 4096 int main(int argc, char** argv) { int sockfd, n,rec_len; char recvline[4096], sendline[4096]; char buf[MAXLINE]; www.2cto.com struct sockaddr_in servaddr; if( (sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0){ printf("create socket error: %s(errno: %d)\n", strerror(errno),errno); exit(0); } memset(&servaddr, 0, sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_port = htons(8000); //可以使用:inet_pton(AF_INET, "127.0.0.1", servaddr.sin_addr); servaddr.sin_addr.s_addr = inet_addr("127.0.0.1");//將字串形式的IP地址轉換為按網路位元組順序的整形值 connect(sockfd, (struct sockaddr*)&servaddr, sizeof(servaddr)) ; printf("send msg to server: \n"); fgets(sendline, 4096, stdin); send(sockfd, sendline, strlen(sendline)); irec_len = recv(sockfd, buf, MAXLINE,0); buf[rec_len] = '\0'; printf("Received : %s ",buf); close(sockfd); www.2cto.com } 三、主機位元組順序格式(HBO,Host Byte Order) 主機位元組順序格式顧名思義,其IP地址的格式是和具體主機或者路由器相關的。對於不同的主機,在進行IP地址的儲存時有不同的格式,比如對於 Motorola 68k系列主機,其HBO與NBO是相同的。而對於Intel x86系列,HBO與NBO則正好相反。 在Socket程式設計中,有四個函式來完成主機位元組順序格式和網路位元組順序格式之間的轉換,它們是:htonl、htons、ntohl、和ntohs。 htons和ntohs完成16位無符號數的相互轉換,htonl和ntohl完成32位無符號數的相互轉換。 在實際應用中我們常見到將埠號轉換的例子(如上例)。這是因為,如果使用者輸入一個數字,而且將指定使用這一數字作為埠號,應用程式則必須在使用它建立地址以前,把它從主機位元組順序轉換成網路位元組順序(使用htons()函式),以遵守TCP/IP協議規定的儲存標準。相應地,如果應用程式希望顯示包含於某一地址中的埠號(例如從getpeername()函式中返回的),這一埠號就必須在被顯示前從網路順序轉換到主機順序(使用ntohs()函式)。 那麼,對於IP地址,主機位元組順序格式的轉換又有哪些應用呢? 應用一,如果想知道從202.156.2.23到202.156.9.65這兩個IP之間到底有多少個主機地址怎麼辦?這時就可以將兩個IP地址轉換為主機位元組順序的格式然後相減來得到,具體的實現如下: int GetIPCount(char * ip1,char * ip2) { long pp;; long ss;; pp = ntohl(inet_addr(ip1));; ss = ntohl(inet_addr(ip2));; return(ss - pp + 1);; } 應用二,如果對一個網段進行掃描,比如,當前正在掃描202.156.23.255,怎麼讓程式知道下一個應掃的IP是202.156.24.0?這時可以將當前IP轉換成主機位元組順序格式並加1後,在轉換回網路格式 即可,具體實現如下: char * GetNextIp(char * m_curip) { struct sockaddr_in in;; long pp;; www.2cto.com char * re;; pp = ntohl(inet_addr(m_curip));; pp = pp + 1;; in.sin_addr.s_addr = htonl(pp);; re = inet_ntoa(in.sin_addr);; return (re);; } 總結 本文介紹了IP地址的三種不同表示格式,包括各種格式產生的原因、具體含義以及在Socket程式設計開發中的一些應用。在實際應用中,必須遵循應用時所應採用的格式標準,同時還應靈活運用格式間的相互轉換以及計算技巧。