IP地址的三種表示格式及在Socket編程中的應用

   使用TCP/IP協議進行網絡應用開發的朋友首先要面對的就是對IP地址信息的處理。IP地址其實有三種不同的表示格式:

       1)Ascii(網絡點分字符串)-

       2) 網絡地址(32位無符號整形,網絡字節序,大頭)

       3)主機地址 (主機字節序)  

       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   

      點分表示:       202.101.105.66   

二、網絡字節順序格式(NBO,Network   Byte   Order)  

       網絡字節順序格式和主機字節順序格式一樣,都只在進行網絡開發中才會遇到。因此,在下面的介紹中,我假設讀者對Socket編程知識有一定的基礎。   
      在網絡傳輸中,TCP/IP協議在保存IP地址這個32位二進制數時,協議規定采用在低位存儲地址中包含數據的高位字節的存儲順序(大頭),這種順序格式就被稱為網絡字節順序格式。在實際網絡傳輸時,數據按照每32位二進制數為一組進行傳輸,由于存儲順序的影響,實際的字節傳輸順序是由高位字節到低位字節的傳輸順序。   為了使通信的雙方都能夠理解數據分組所攜帶的源地址、目的地址以及分組的長度等二進制信息,無論是主機還是路由器,在發送每一個分組以前,都必須將二進制信息轉換為TCP/IP標準的網絡字節順序格式。網絡字節順序格式的地址不受主機、路由器類型的影響,它的表示是唯一的。   
1.jpg

在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.0×12”。   

 我們在前面的socket編程提到client端的代碼,連接本地端口:

/* 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];  
    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]  = '';  
    printf("Received : %s ",buf);  
    close(sockfd);  
}

三、主機字節順序格式(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;;     
      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編程開發中的一些應用。在實際應用中,必須遵循應用時所應采用的格式標準,同時還應靈活運用格式間的相互轉換以及計算技巧。

字節序相關知識

 1)字節序

          字節序又稱端序,尾序,英文:Endianness。在計算機科學領域中,字節序是指存放多字節數據的字節(byte)的順序,典型的情況是整數在內存中的存放方式和網絡傳輸傳輸順序。Endianness有時候也可以用指位序(bit)。

        一般而言,字節序指示了一個UCS-2字符的哪個字節存儲在低地址。如果LSByte 在MSByte的前面,即LSB為低地址,則該字節序是小端序;反之則是大端序。在網絡編程中,字節序是一個必須被考慮的因素,因為不同的處理器體系可能采用不同的字節序。在多平臺的代碼編程中,字節序可能會導致難以察覺的bug。

名詞:

最低有效位the least significant bitlsb):是指一個二進制數字中的第0位(即最低位),具有權值為2^0,可以用它來檢測數的奇偶性。與之相反的稱之為最高有效位。在大端序中,lsb指最右邊的位。

最高有效位the Most Significant Bit,msb):是指一個n位二進制數字中的n-1位,具有最高的權值2^{n-1}。與之相反的稱之為最低有效位。在大端序中,msb即指最左端的位。

對于有符號二進制數,負數采用反碼補碼形式,此時msb用來表示符號,msb為1表示負數,0表示正數

單字節(abyte):大部分處理器以相同的順序處理位元(bit),因此單字節的存放方法和傳輸方式一般相同。

多字節:如整數(32位機中一般占4字節),多字節對象被存儲為連續的字節序列,數據的內存地址則是該內存地址的最小地址。

如long型數據的地址是ox001, ox002, ox003,ox004。則該數據的內存地址是ox001。

在不同的處理器的存放多字節數據的方式主要有兩種:

大端序(英文名稱為big endian)指從最高位起存,位數最大的數字在最前,即高字節存于內存低地址,低字節存于內存高地址, 從最高有效字節到最低有效字節的順序存儲對象。

小端序(英文名稱為little endian)指從對低位起存,位數最小的數字在最前。 即低字節存于內存低地址,高字節存于內存高地址,從最低有效字節到最高有效字節的順序存儲對象。

簡單打個比方說,十進制數12345。1的位數最高,是萬位;5的位數最低,是個位。 

大端序的話,就是從萬位開始存,表示為12345; 
小端序的話,就是從各位開始存,表示為54321.

再如一個long型數據0x12345678的存儲表示:

大端序存儲表示:

 內存地址數據內存低地址–>    a0x00112a+10x00234a+20×00356內存高地址–>a+30×00478

小端序的存儲表示:

 內存地址數據內存低地址–>a0x00178a+10x00256a+20×00334內存高地址–>a+30×00412

2)網絡序

網絡傳輸一般采用大端序,也被稱之為網絡字節序,或網絡序IP協議中定義大端序為網絡字節序。

socketAPI定義了一組轉換函數,用于16和32bit整數在網絡序和本機字節序之間的轉換。htonl,htons用于本機序轉換到網絡序;ntohl,ntohs用于網絡序轉換到本機序。

3)位序

一般用于描述串行設備的傳輸順序。一般硬件傳輸采用小端序(先傳低位),但I2C協議采用大端序。網絡協議中只有數據鏈路層的底端會涉及到。

4)處理器體系

 1)小端序體系x86MOS Technology 6502,Z80VAX,PDP-11等處理器為Littleendian。

 2)大端序體系Motorola 6800,Motorola 68000PowerPC 970,System/370,SPARC(除V9外)等處理器為Big endian

 3)可配置:ARMPowerPC (除PowerPC 970外), DEC AlphaSPARCV9MIPSPA-RISC and IA64的字節序是可配置的。

5) 編程判斷大端序和小端序

#include <stdio.h>  
  
bool IsBigEndian(long a)  
{  
    if(((char *)&a)[3] == 1)  
        return true ;  
    else  
        return false ;  
}  
  
void main(){  
    bool b ;  
    long a = 0x12345678;   
    b = IsBigEndian(a );  
    printf("%d", &a);  
}

打開VS的內存窗口,查看內存存儲方式:

設定斷點:

2.jpg打開 debug——>window——>Memory

3.jpg

查看變量a 的地址:0x002BFE50

4.jpg

查看內存地址:

5.jpg

從上面看出我使用的x86 ,是小端序。

從而驗證 b =false是正確的。

轉自:http://blog.csdn.net/hguisu/article/details/7449955

原創文章,作者:s19930811,如若轉載,請注明出處:http://www.www58058.com/2988

(0)
s19930811s19930811
上一篇 2015-04-10 21:19
下一篇 2015-04-10 21:19

相關推薦

  • Linux文件管理命令和bash基礎特性

    1、Linux上的文件管理命令都有哪些,其常用的使用方法及其相關示例演示  文件管理命令:mkdir,rmdir,cp,mv,rm,cat,tac,head,tail,more,less mkdir命令:   mkdir – make directories   mkdir [OPTION]… DIREC…

    2017-07-13
  • 文件查找:find命令、locate命令;Linux文件系統上的權限

    文件查找:find、locate locate:依賴事先構建的索引,是在系統空閑周期性自動進行;手動更新(updatedb);極其消耗資源;   find [option]… [查找路徑] [查找條件] [處理動作] 查找條件: 根據文件名查找: -name “文件名稱”:支持使用通配符glob(*,?,[],[…

    Linux干貨 2017-12-14
  • 分布式文件系統之MogileFS

    MogileFS是一個開源的分布式文件存儲系統,由LiveJournal旗下的Danga Interactive公司開發。Danga團隊開發了包括 Memcached、MogileFS、Perlbal 等多個知名的開源項目。目前使用MogileFS 的公司非常多,如日本排名先前的幾個互聯公司及國內的yupoo(又拍)、digg、豆瓣、1號店、大眾點評、搜狗和…

    Linux干貨 2017-06-16
  • 關于大型網站技術演進的思考(一):存儲的瓶頸(1)

    原文出處: 夏天的森林  前不久公司請來了位互聯網界的技術大牛跟我們做了一次大型網站架構的培訓,兩天12個小時信息量非常大,知識的廣度和難度也非常大,培訓完后我很難完整理出全部聽到的知識,今天我換了個思路是回味這次培訓,這個思路就是通過本人目前的經驗和技術水平來思考下大型網站技術演進的過程。 首先我們要思考一個問題,什么樣的網站才是大型網…

    Linux干貨 2015-02-26
  • 馬哥教育網絡班22期+第12周課程練習

    1、請描述一次完整的http請求處理過程; 1. 建立或處理連接:接收請求或拒絕請求; 2. 接收請求:接收來自于網絡上的主機請求報文中對某特定資源的一次請求的過程; 3. 處理請求:對請求報文進行解析,獲取客戶端請求的資源及請求方法等相關信息; 4. 訪問資源:獲取請求報文中請求的資源; 5. 構建響應報文…

    Linux干貨 2016-11-28
欧美性久久久久