參考文章:
使用tcp/ip協議進行網路應用開發的朋友首先要面對的就是對ip位址資訊的處理。ip位址其實有三種不同的表示格式:
1)ascii(網路點分字串)-
2) 網路位址(32位無符號整形,網路位元組序,大頭)
3)主機位址 (主機位元組序)
ip位址是ip網路中資料傳輸的依據,它標識了ip網路中的乙個連線,一台主機可以有多個ip位址,ip分組中的ip位址在網路傳輸中將保持不變。下面具體介紹ip位址的三種不同表示格式。
這是我們最常見的表示格式,比如某機的ip位址可能為「202.101.105.66」。事實上,對於ipv4(ip版本)來說,ip位址是由乙個32位的二進位制數所構成,但這樣一串數字序列無疑是十分冗長並且難以閱讀和記憶的。為了方便人們的記憶和使用,就將這串數字序列分成4組,每組8位,並改為用 10進製數進行表示,最後用小原點隔開,於是就演變成了「點分10進製表示格式」。
11001010011001010110100101000010
分成4組後: 11001010 01100101 01101001 01000010
十進位制表示: 202 101 105 66
點分表示: 202.101.105.66
網路位元組順序格式和主機位元組順序格式一樣,都只在進行網路開發中才會遇到。因此,在下面的介紹中,我假設讀者對socket程式設計知識有一定的基礎。
在網路傳輸中,tcp/ip協議在儲存ip位址這個32位二進位制數時,
協議規定採用在低位儲存位址中包含資料的高位位元組的儲存順序(大頭),這種順序格式就被稱為網路位元組順序格式。在實際網路傳輸時,資料按照每32位二進位制數為一組進行傳輸,由於儲存順序的影響,
實際的位元組傳輸順序是由高位位元組到低位位元組的傳輸順序。 為了使通訊的雙方都能夠理解資料分組所攜帶的源位址、目的位址以及分組的長度等二進位制資訊,無論是主機還是路由器,在傳送每乙個分組以前,都必須將二進位制資訊轉換為tcp/ip標準的網路位元組順序格式。網路位元組順序格式的位址不受主機、路由器型別的影響,它的表示是唯一的。
在socket程式設計開發中,通過函式inet_addr和inet_ntoa可以實現點分字串與網路位元組順序格式ip位址之間的轉換。
inet_addr函式原型如下:
[cpp]view plain
copy
print?
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程式設計提到client端的**,連線本地埠:
[cpp]view plain
copy
print?
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)) ;
主機位元組順序格式顧名思義,其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位址轉換為主機位元組順序的格式然後相減來得到,具體的實現如下:
[cpp]view plain
copy
print?
int getipcount(char * ip1,char * ip2)
應用二,如果對乙個網段進行掃瞄,比如,當前正在掃瞄202.156.23.255,怎麼讓程式知道下乙個應掃的ip是202.156.24.0?這時可以將當前ip轉換成主機位元組順序格式並加1後,在轉換回網路格式
即可,具體實現如下:
[cpp]view plain
copy
print?
char * getnextip(char * m_curip)
struct in_addr;
struct sockaddr_in; //16
//通用套接字
struct sockaddr;
任何的協議為了擴充套件性,都在協議的包格式中加入了擴充套件字段,即就是保留字段。
ip搜尋路由表的幾個步驟:
1) 搜尋匹配的主機位址;
2) 搜尋匹配的網路位址;
3) 搜尋預設表項(預設表項一般在路由表中被指定為乙個網路表項,其網路號為 0)。
××匹配主機位址步驟始終發生在匹配網路位址步驟之前。
ip層進行的選路實際上是一種【選路機制】,它搜尋路由表並決定向哪個網路介面傳送分組。
這區別於【選路策略】,它只是一組決定把哪些路由放入路由表的規則。ip執行選路機制,而路
由守護程式則一般提供選路策略。
netstat -rn
假如有表項: 目的地是a, 閘道器是b,則代表前往目的地a的包將傳送到b處。
路由表標誌(flags欄位):
u 該路由可用.
g 該路由通過路由**與目的位址相連,無此標誌表示本機與目的位址是直接相連的.
h 該路由的目的位址為主機位址,無此標誌表示目的位址為網路位址.
d 該路由由重定向報文建立.
m 該路由被重定向報文修改.
標識g區別了間接路由和直接路由.有g即為間接路由.發往直接路由的分組包含目的位址的ip和鏈路層位址.發往間接路由的分組包含目的位址的ip,但鏈路層位址為間接路由的位址.
當路由器收到乙份ip資料報但不能**時,將向原始傳送端傳送icmp』主機不可達』差錯報文.
如圖,主機與r2實際上在同乙個區域網下。
1.主機有乙份資料要發往r2,但是由於主機的路由表中沒有r2的資訊,所以資料報發給預設閘道器r1;
2.r1通過自己的路由表發現r2是該ip資料報的下一站;
3.當r1把資料報發給r2時,發現接收主機資料報使用的埠和傳送給r2使用的埠相同(即主機與r2在同一區域網下);
4.r1向主機傳送icmp重定向報文,修改主機的路由表,以後主機直接把資料報發往r2.
1.導致重定向的位址(即icmp重定向報文的資料位於ip資料報的首部);
2.傳送重定向報文的路由器的ip位址(包含重定向資訊的ip資料報中的源位址);
3.應該採用的路由器ip位址(在icmp報文中的4 ~ 7位元組)。
××重定向報文只能由路由器生成,而不能由主機生成。另外,重定向報文是為主機而不是為路由器使用的!
六、網路層作用
網路層所研究和解決的問題:
1.網路層提供給運輸層的服務;
2.路由選擇;
3.流量控制;
4.網路互連;
5.internet中的網路層協議。
總結
介紹了ip位址的三種不同表示格式,包括各種格式產生的原因、具體含義以及在socket程式設計開發中的一些應用。在實際應用中,必須遵循應用時所應採用的格式標準,同時還應靈活運用格式間的相互轉換以及計算技巧。
擴充套件IP位址筆記
內部本地和外部全域性,是通訊中正式的真正源 目的位址內部全域性和外部本地是在nat過程中的乙個中間量 ip nat inside source static 192.168.1.2 202.2.2.252 將從內部網路出去外部網路的資料報的源ip位址進行內部本地 內部全域性的靜態轉 換ip nat ...
閘道器IP位址和IP位址的區別
閘道器,大家都知道,從乙個房間走到另乙個房間,必然要經過一扇門。同樣,從乙個網路向另乙個網路傳送資訊,也必須經過一道 關口 這道關口就是閘道器。顧名思義,閘道器 gateway 就是乙個網路連線到另乙個網路的 關口 按照不同的分類標準,閘道器也有很多種。tcp ip協議裡的閘道器是最常用的,在這裡我...
徹底明白IP位址 IP位址的介紹
徹底明白ip位址 ip位址的介紹 ip位址的介紹 1 ip位址的表示方法 有些人對範圍是2x不太理解,舉個簡單的例子加以說明。如c類網,每個網路允許有28 2 254臺主機是這樣來的。因為c類網的主機位是8位,變化如下 00000000 00000001 00000010 00000011 1111...