《網路協議從入門到底層原理》筆記(五)傳輸層(UDP、TCP、流量控制、擁塞控制、建立連線、釋放連線)
IP服務的特點
IP協議是TCP/IP協議得動力,它為上層協議提供無狀態,無連線,不可靠得服務。
- 無狀態:是指IP通訊雙方不同步傳輸資料的狀態資訊,因此所有IP資料報的傳送,傳輸,和接收都是相互獨立的,沒有山下文關係的。傳送、傳輸和接收都是相互獨立、沒有上下文關係的。這種服務最大的缺點是無法處理亂序和重複的IP資料報。比如傳送端傳送出的第N個IP資料報可能比第N+1個IP資料報後到達接收端,而同一個IP資料報也可能經過不同的路徑多次到達接收端。在這兩種情況下,接收端的IP模組無法檢測到亂序和重複,因為這些IP資料報之間沒有任何上下文關係。接收端的IP模組只要收到了完整的IP資料報(如果是IP分片的話,IP 模組將先執行重組),就將其資料部分(TCP報文段、UDP資料報或者1CMP報文),上交給上層協議。那麼從上層協議來看,這些資料就可能是亂序的、重複的。面向連線的協議,比如TCP協議,則能夠自己處理亂序的、重複的報文段,它遞交給上層協議的內容絕對是有序的、正確的。雖然IP資料報頭部提供了一個標識欄位(見後文)用以唯-標識-一個IP資料報,但它是被用來處理IP分片和重組的,而不是用來指示接收順序的。無狀態服務的優點也很明顯:簡單、高效。我們無須為保持通訊的狀態而分配一些核心資源,也無須每次傳輸資料時都攜帶狀態資訊。在網路協議中,無狀態是很常見的,比如UDP協議和HTTP協議都是無狀態協議。以HTTP協議為例,一個瀏覽器的連續兩次網頁請求之間沒有任何關聯,它們將被Web伺服器獨立地處理。
- 無連線(connectionless)是指IP通訊雙方都不長久地維持對方的任何資訊。這樣,上層協議每次傳送資料的時候,都必須明確指定對方的IP地址。
- 不可靠是指IP協議不能保證IP資料報準確地到達接收端,它只是承諾盡最大努力(best effort)。 很多種情況都能導致IP資料報傳送失敗。比如,某個中轉路由器發現IP資料報在網路上存活的時間太長(根據IP資料報頭部欄位TTL判斷,見後文),那麼它將丟棄之,並返回一個ICMP錯誤訊息(超時錯誤)給傳送端。又比如,接收端發現收到的IP資料報不正確(通過校驗機制),它也將丟棄之,並返回一個ICMP錯誤訊息(IP 頭部引數錯誤)給傳送端。無論哪種情況,傳送端的IP模組一旦檢測到IP資料報傳送失敗,就通知上層協議傳送失敗,而不會試圖重傳。因此,使用IP服務的上層協議(比如TCP協議)需要自己實現資料確認、超時重傳等機制以達到可靠傳輸的目的。
IPv4頭部結構
- 4位版本號(version) 指定IP協議的版本。對IPv4來說,其值是4。
- 4位頭部長度(header length)標識該IP頭部有多少個32 bit字(4位元組)。因為4位最大能表示15,所以IP頭部最長是60位元組。
- 8位服務型別(Type Of Service, TOS)包括- -個 3位的優先權欄位(現在已經被忽略), 4位的TOS欄位和1位保留欄位(必須置0)。4位的TOS欄位分別表示:最小延時,最大吞吐量,最高可靠性和最小費用。其中最多有一個能置為1,應用程式應該根據實際需要來設定它。比如像ssh和telnet這樣的登入程式需要的是最小延時的服務,而檔案傳輸程式ftp則需要最大吞吐量的服務。
- 16位總長度(total length) 是指整個IP資料報的長度,以位元組為單位,因此IP資料報的最大長度為65535 (2l6-1) 位元組。但由於MTU的限制,長度超過MTU的資料報都將被分片傳輸,所以實際傳輸的IP資料報(或分片)的長度都遠遠沒有達到最大值。接下來的3個欄位則描述瞭如何實現分片。
- 16位標識(identif.cation) 唯一地標識主機發送的每個一資料報。其初始值由系統隨機生成:每傳送一個數據報,其值就加1。該值在資料報分片時被複制到每個分片中,因此同一個資料報的所有分片都具有相同的標識值。
- 3位標誌欄位的第- -位保留。第二位(Don't Fragment,DF)表示“禁止分片”。如果設定了這個位,IP 模組將不對資料報進行分片。在這種情況下,如果IP資料報長度超過MTU的話,IP 模組將丟棄該資料報並返回一ICMP差錯報文。第三位(More Fragment, MF)表示“更多分片”。除了資料報的最後- -個分片外,其他分片都要把它置1。
- 13位分片偏移(fragmentationoffset)是分片相對原始IP資料報開始處(僅指資料部分)的偏移。實際的偏移值是該值左移3位(乘8)後得到的。由於這個原因,除了最後- -個IP分片外,每個IP分片的資料部分的長度必須是8的整數倍(這樣才能保證後面的IP分片擁有一個合適的偏移值)。
- 8位生存時間(TimeToLive,TTL)是資料報到達目的地之前允許經過的路由器跳數。TTL值被髮送端設定(常見的值是64)。資料報在轉發過程中每經過一個路由,該值就被路由器減1。當TTL值減為0時,路由器將丟棄資料報,並向源端傳送-一個ICMP差錯報文。TTL值可以防止資料報陷人路由迴圈。
- 8位協議( protocol)用來區分上層協議。/etc/protocols 檔案定義了所有上層協議對應的protocol欄位的數值。其中,ICMP是1, TCP是6,UDP是17。/etc/protocols檔案是RFC 1700的-一個子集。
- 16位頭部校驗和(header checksum)由傳送端填充,接收端對其使用CRC演算法以檢驗IP資料報頭部(注意,僅檢驗頭部)在傳輸過程中是否損壞。
- 32位的源端IP地址和目的端IP地址用來標識資料報的傳送端和接收端。一般情況下,這兩個地址在整個資料報的傳遞過程中保持不變,而不論它中間經過多少箇中轉路由器。
- IPv4最後一個選項欄位(option) 是可變長的可選資訊。這部分最多包含40位元組,因為IP頭部最長是60位元組(其中還包含前面討論的20位元組的固定部分)。可用的IP選項包括:
- 記錄路由(recordroute),告訴資料報途經的所有路由器都將自己的IP地址填人IP頭部的選項部分,這樣我們就可以跟蹤資料報的傳遞路徑。
- 時間戳(timestamp),告訴每個路由器都將資料報被轉發的時間(或時間與IP地址對)填人IP頭部的選項部分,這樣就可以測量途經路由之間資料報傳輸的時間。
- 鬆散源路由選擇(loose source routing),指定- -個路由 器IP地址列表,資料報傳送過程中必須經過其中所有的路由器。
- 嚴格源路由選擇(strict source routing),和鬆散源路由選擇類似,不過資料報只能經過被指定的路由器。
IP分片
當IP資料報的長度超過幀的MtU時,它將被分片傳輸。分片可能發生在傳送端,也可能發生在中轉路由器上,而且可能在傳輸過程中被多次分片,但只有在最終的目標機器上,這些分片才會被核心中的IP模組重新組裝。
IP頭部中的如下三個欄位給IP的分片和重組提供了足夠的資訊:資料報標識、標誌和片偏移。一個IP資料報的每個分片都具有自己的IP頭部,它們具有相同的標識值,但具有不同的片偏移。並且除了最後一個分片外,其他分片都將設定MP標誌。此外,每個分片的IP頭部的總長度欄位將被設定為該分片的長度。
乙太網幀的MTU是1500位元組( 可以通過ifconfig命令或者netstat命令檢視),因此它攜帶的IP資料報的資料部分最多是1480 位元組(IP 頭部佔用20位元組)。考慮用IP資料報封裝一個長度為1481位元組的ICMP報文(包括8位元組的ICMP頭部,所以其資料部分長度為1473位元組),則該資料報在使用乙太網幀傳輸時必須被分片。
長度為1501位元組的IP資料報被拆分成兩個IP分片,第一個IP分片長度為1500位元組,第二個IP分片的長度為21位元組。每個IP分片都包含自己的IP頭部(20 位元組),且第--個IP分片的IP頭部設定了MF標誌,而第二個IP分片的IP頭部則沒有設定該標誌,因為它已經是最後-一個分片了。原始IP資料報中的ICMP頭部內容被完整地複製到了第一個IP分片中。第二個IP分片不包含ICMP頭部資訊,因為IP模組重組該ICMP報文的時候只需要- .份ICMP頭部資訊,重複傳送這個資訊沒有任何益處。1473 位元組的ICMP報文資料的前1472位元組被IP模組複製到第-一個IP分片中,使其總長度為1500位元組,從而滿足MTU的要求;而多出的最後1位元組則被複制到第二個IP分片中。
IP路由
IP模組工作流程
我們從右往左來分析圖。當IP模組接收到來自資料鏈路層的IP資料報時,它首先對該資料報的頭部做CRC校驗,確認無誤之後就分析其頭部的具體資訊。
如果該IP資料報的頭部設定了源站選路選項(鬆散源路由選擇或嚴格源路由選擇),則IP模組呼叫資料報轉發子模組來處理該資料報。如果該IP資料報的頭部中目標IP地址是本機的某個IP地址,或者是廣播地址,即該資料報是傳送給本機的,則IP模組就根據資料報頭部中的協議欄位來決定將它派發給哪個上層應用(分用)。如果IP模組發現這個資料報不是傳送給本機的,則也呼叫資料報轉發子模組來處理該資料報。
資料報轉發子模組將首先檢測系統是否允許轉發,如果不允許, IP模組就將資料報丟棄。如果允許,資料報轉發子模組將對該資料報執行一些操作,然後將它交給IP資料報輸出子模組。我們將在後面討論資料報轉發的具體過程。
IP資料報應該傳送至哪個下一跳路由(或者目標機器),以及經過哪個網絡卡來發送,就是IP路由過程,即圖中“計算下一-跳路由”子模組。IP 模組實現資料報路由的核心資料結構是路由表。這個表按照資料報的目標IP地址分類,同--型別的IP資料報將被髮往相同的下一跳路由器(或者目標機器)。我們將在後面討論IP路由過程。
IP輸出佇列中存放的是所有等待發送的IP資料報,其中除了需要轉發的IP資料報外,還包括封裝了本機上層資料(ICMP報文、TCP報文段和UDP資料報)的IP資料報。
圖中的虛線箭頭顯示了路由表更新的過程。這一過程是指通過路由協議或者route:命令調整路由表,使之更適應最新的網路拓撲結構,稱為IP路由策略。
路由機制
cmf@cmf-virtual-machine:~$ route
核心 IP 路由表
目標 閘道器 子網掩碼 標誌 躍點 引用 使用 介面
default 192.168.26.2 0.0.0.0 UG 100 0 0 ens33
link-local 0.0.0.0 255.255.0.0 U 1000 0 0 ens33
192.168.26.0 0.0.0.0 255.255.255.0 U 100 0 0 ens33
路由表中,第一項的目標地址是default,即所謂的預設路由項。該項包含一個“G"標誌,說明路由的下一跳目標是閘道器,其地址是192.168.26.2 (這是測試網路中路由器的本地IP地址)。另外一個路由項的目標地址是192.168.26.0, 它指的是本地區域網。如果該路由項的閘道器地址為*,說明資料報不需要路由中轉,可以直接傳送到目標機器。
那麼路由表是如何按照IP地址分類的呢?或者說給定資料報的目標IP地址,它將匹配路由表中的哪-項呢?這就是IP的路由機制,分為3個步驟:
- 1)查詢路由表中和資料報的目標IP地址完全匹配的主機IP地址。如果找到,就使用該路由項,沒找到則轉步驟2。
- 2)查詢路由表中和資料報的目標IP地址具有相同網路ID的網路IP地址所示的路由表中的第二項)。如果找到,就使用該路由項:沒找到則轉步驟3。
- 3)選擇預設路由項,這通常意味著資料報的下一跳路由是閘道器。因此,對於測試而言,所有傳送到IP地址為192.168.1.*的機器的IP資料報都可以直接傳送到目標機器(匹配路由表第二項),而所有訪問因特網的請求都將通過閘道器來轉發(匹配預設路由項)。
IP轉發
不是傳送給本機的IP資料報將由資料報轉發子模組來處理。路由器都能執行資料報的轉發操作,而主機一般只發送和接收資料報,這是因為主機上/proc/sys/ne/ipv4/ip_forward核心引數預設被設定為0。我們可以通過修改它來使能主機的資料報轉發功能
sudo echo 1 > /proc/sys/net/ipv4/ip_forward
對於允許IP資料報轉發的系統( 主機或路由器),資料報轉發子模組將對期望轉發的資料報執行以下操作:
- 檢查資料報頭部的TTL值。如果TTL值已經是0,則丟棄該資料報。
- 檢視資料報頭部的嚴格源路由選擇選項。如果該選項被設定,則檢測資料報的目標IP地址是否是本機的某個IP地址。如果不是,則傳送-一個ICMP源站選路失敗報文給傳送端。
- 如果有必要,則給源端傳送一個ICMP重定向報文,以告訴它-一個更合理的下一跳路由器。
- 將TTL值減1。
- 處理IP頭部選項。
- 如果有必要,則執行IP分片操作。
重定向
ICMP重定向報文的型別值是5,程式碼欄位有4個可選值,用來區分不同的重定向型別。主機重定向,其程式碼值為1。ICMP重定向報文的資料部分含義很明確,它給接收方提供瞭如下兩個資訊:
- 引起重定向的IP資料報(即圖2-4中的原始IP資料報)的源端IP地址。
- 應該使用的路由器的IP地址。
接收主機根據這兩個資訊就可以斷定引起重定向的IP資料報應該使用哪個路由器來轉發,並且以此來更新路由表(通常是更新路由表緩衝,而不是直接更改路由表)。/proc/sys/net/ipv4/confall/send_redirects 核心引數指定是否允許傳送ICMP重定向報文,而/proc/sys/netipv4/confal/accept_redirects 核心引數則指定是否允許接收ICMP重定向報文。一般來說,主機只能接收ICMP重定向報文,而路由器只能傳送ICMP重定向報文。
IPv6頭部結構
- 4位版本號(version) 指定IP協議的版本。對IPv6來說,其值是6。
- 8位通訊型別(raffic class)指示資料流通訊型別或優先順序,和IPv4中的Tos類似。
- 20位流標籤(flow label)是IPv6新增加的欄位,用於某些對連線的服務質量有特殊要求的通訊,比如音訊或視訊等實時資料傳輸。
- 16位淨荷長度(payload length)指的是IPv6 擴充套件頭部和應用程式資料長度之和,不包括固定頭部長度。
- 8位下一一個包頭(next header)指出緊跟IPv6固定頭部後的包頭型別,如擴充套件頭(如果有的話)或某個上層協議頭(比如TCP, UDP或ICMP)。它類似於IPv4頭部中的協議欄位,且相同的取值有相同的含義。
- 8位跳數限制(hop limit)和IPv4中的TTL含義相同。
- IPv6用128位(16位元組)來表示IP地址,使得IP地址的總量達到了28個。所以有人說,“IPv6 使得地球上的每粒沙子都有一-個IP地址”。
- 32位表示的IPv4地址一般用點分十進位制來表示,而IPv6地址則用十六進位制字串表示,比如“FE80:000:000:0000: 1234:56780000:0012”。可見,IPv6地址用“:”分割成8組,每組包含2位元組。但這種表示方法過於麻煩,通常可以使用所謂的零壓縮法來將其簡寫,也就是省略連續的、全零的組。比如,上 面的例子使用零壓縮法可表示為“FE80: 1234:56780000:0012”.不過零壓縮法對一個IPv6地址只能使用一次, 比如上面的例子中,位元組組“5678"後面的全零組就不能再省略,否則我們就無法計算每個“:”之間省略了多少個全零組。
IPv6拓展頭部
可變長的擴充套件頭部使得IPv6能支援更多的選項,並且很便於將來的擴充套件需要。它的長度可以是0,表示資料報沒使用任何擴充套件頭部。一個數據報可以包含多個擴充套件頭部,每個擴充套件頭部的型別由前一個頭部(固定頭部或擴充套件頭部)中的下一-個報頭欄位指定。目前可以使用的擴充套件頭部如表所示。