1. 程式人生 > 其它 >003 TCP/IP協議詳解(二)

003 TCP/IP協議詳解(二)

一、ping

ping可以說是ICMP的最著名的應用,是TCP/IP協議的一部分。利用“ping”命令可以檢查網路是否連通,可以很好地幫助我們分析和判定網路故障。

例如:當我們某一個網站上不去的時候。通常會ping一下這個網站。ping會回顯出一些有用的資訊。一般的資訊如下:

ping這個單詞源自聲納定位,而這個程式的作用也確實如此,它利用ICMP協議包來偵測另一個主機是否可達。原理是用型別碼為0的ICMP發請 求,受到請求的主機則用型別碼為8的ICMP迴應。

ping程式來計算間隔時間,並計算有多少個包被送達。使用者就可以判斷網路大致的情況。我們可以看到, ping給出來了傳送的時間和TTL的資料。

IP資料報中的RR選項的一般格式如圖 7 - 3所示。

code是一個位元組,指明 IP選項的型別。對於 RR選項來說,它的值為7lenR R選項總字
節長度,在這種情況下為 39(儘管可以為 RR選項設定比最大長度小的長度,但是ping程式
總是提供 3 9位元組的選項欄位,最多可以記錄 9IP地址。由於 I P首部中留給選項的空間有限,
它一般情況都設定成最大長度)。
ptr稱作指標欄位。它是一個基於 1的指標,指向存放下一個 IP地址的位置。它的最小值為
4,指向存放第一個 I P地址的位置。隨著每個 IP地址存入清單, ptr的值分別為 81216,最
大到36。當記錄下9IP地址後, ptr的值為40,表示清單已滿。
當路由器(根據定義應該是多穴的)在清單中記錄 IP地址時,它應該記錄哪個地址呢?
是入口地址還是出口地址?為此, RFC 791 [Postel 1981a]指定路由器記錄出口 IP地址。

IP時間戳選項與記錄路由選項類似。 I P時間戳選項的格式如圖 7 - 7所示(請與圖7 - 3進行比較)。

時間戳選項的程式碼為 0 x 4 4。其他兩個欄位 l e np t r與記錄路由選項相同:選項的總長度
(一般為3 64 0)和指向下一個可用空間的指標( 591 3等)。
接下來的兩個欄位是 4 bit的值: O F表示溢位欄位, F L表示標誌欄位。時間戳選項的操作
根據標誌欄位來進行,如圖 7 - 8所示。

二、Traceroute

Traceroute是用來偵測主機到目的主機之間所經路由情況的重要工具,也是最便利的工具。

Traceroute的原理是非常非常的有意思,它收到到目的主機的IP後,首先給目的主機發送一個TTL=1的UDP資料包,而經過的第一個路由器收到這個資料包以後,就自動把TTL減1,而TTL變為0以後,路由器就把這個包給拋棄了,並同時產生 一個主機不可達的ICMP資料報給主機。主機收到這個資料報以後再發一個TTL=2的UDP資料報給目的主機,然後刺激第二個路由器給主機發ICMP資料 報。如此往復直到到達目的主機。這樣,traceroute就拿到了所有的路由器IP。

三、DNS

DNS(Domain Name System,域名系統),因特網上作為域名和IP地址相互對映的一個分散式資料庫,能夠使使用者更方便的訪問網際網路,而不用去記住能夠被機器直接讀取的IP數串。通過主機名,最終得到該主機名對應的IP地址的過程叫做域名解析(或主機名解析)。DNS協議執行在UDP協議之上,使用埠號53。

四、TCP流量控制

如果傳送方把資料傳送得過快,接收方可能會來不及接收,這就會造成資料的丟失。

TCP流量控制主要是針對接收端的處理速度不如傳送端傳送速度快的問題,消除傳送方使接收方快取溢位的可能性。

TCP流量控制主要使用滑動視窗協議,滑動視窗是接受資料端使用的視窗大小,用來告訴傳送端接收端的快取大小,以此可以控制傳送端傳送資料的大小,從而達到流量

控制的目的。這個視窗大小就是我們一次傳輸幾個資料。對所有資料幀按順序賦予編號,傳送方在傳送過程中始終保持著一個傳送視窗,只有落在傳送視窗內的幀才允許被髮送;

同時接收方也維持著一個接收視窗,只有落在接收視窗內的幀才允許接收。這樣通過調整發送方視窗和接收方視窗的大小可以實現流量控制。

設A向B傳送資料。在連線建立時,B告訴了A:“我的接收視窗是 rwnd = 400 ”(這裡的 rwnd 表示 receiver window) 。因此,傳送方的傳送視窗不能超過接收方給出的接收視窗的數值。請注意,TCP的視窗單位是位元組,不是報文段。假設每一個報文段為100位元組長,而資料報文段序號的初始值設為1。大寫ACK表示首部中的確認位ACK,小寫ack表示確認欄位的值ack。


從圖中可以看出,B進行了三次流量控制。第一次把視窗減少到 rwnd = 300 ,第二次又減到了 rwnd = 100 ,最後減到 rwnd = 0 ,即不允許傳送方再發送資料了。這種使傳送方暫停傳送的狀態將持續到主機B重新發出一個新的視窗值為止。B向A傳送的三個報文段都設定了 ACK = 1 ,只有在ACK=1時確認號欄位才有意義。

TCP為每一個連線設有一個持續計時器(persistence timer)。只要TCP連線的一方收到對方的零視窗通知,就啟動持續計時器。若持續計時器設定的時間到期,就傳送一個零視窗控測報文段(攜1位元組的資料),那麼收到這個報文段的一方就重新設定持續計時器

五、TCP擁塞控制

流量控制是通過接收方來控制流量的一種方式;而擁塞控制則是通過傳送方來控制流量的一種方式。

TCP傳送方可能因為IP網路的擁塞而被遏制,TCP擁塞控制就是為了解決這個問題(注意和TCP流量控制的區別)。

TCP擁塞控制的幾種方法:慢啟動,擁塞避免,快重傳和快恢復。

這裡先理解一個概念:擁塞視窗

擁塞視窗:傳送方維持一個叫做擁塞視窗 cwnd的狀態變數。擁塞視窗的大小取決於網路的擁塞程度,並且動態變化。

傳送方的讓自己的傳送視窗=min(cwnd,接受端接收視窗大小)。說明:傳送方取擁塞視窗與滑動視窗的最小值作為傳送的上限。

傳送方控制擁塞視窗的原則是:只要網路沒有出現擁塞,擁塞視窗就增大一些,以便把更多的分組傳送出去。但只要網路出現擁塞,擁塞視窗就減小一些,以減少

注入到網路中的分組數。

下面將討論擁塞視窗cwnd的大小是怎麼變化的。

1、慢啟動

TCP在連線過程的三次握手完成後,開始傳資料,並不是一開始向網路通道中傳送大量的資料包。因為假如網路出現問題,很多這樣的大包會積攢在路由器上,很容易導致網

絡中路由器快取空間耗盡,從而發生擁塞。因此現在的TCP協議規定了,新建立的連線不能夠一開始就傳送大尺寸的資料包,而只能從一個小尺寸的包開始傳送,在傳送和資料被

對方確認的過程中去計算對方的接收速度,來逐步增加每次傳送的資料量(最後到達一個穩定的值,進入高速傳輸階段。相應的,慢啟動過程中,TCP通道處在低速傳輸階段),

以避免上述現象的發生。這個策略就是慢啟動。

畫個簡單的圖從原理上粗略描述一下

傳送方維持一個擁塞視窗 cwnd ( congestion window )的狀態變數。擁塞視窗的大小取決於網路的擁塞程度,並且動態地在變化。傳送方讓自己的傳送視窗等於擁塞視窗。

傳送方控制擁塞視窗的原則是:只要網路沒有出現擁塞,擁塞視窗就再增大一些,以便把更多的分組傳送出去。但只要網路出現擁塞,擁塞視窗就減小一些,以減少注入到網路中的分組數。

慢啟動演算法:
當主機開始傳送資料時,如果立即所大量資料位元組注入到網路,那麼就有可能引起網路擁塞,因為現在並不清楚網路的負荷情況。
因此,較好的方法是 先探測一下,即由小到大逐漸增大發送視窗,也就是說,由小到大逐漸增大擁塞視窗數值。

通常在剛剛開始傳送報文段時,先把擁塞視窗 cwnd 設定為一個最大報文段MSS的數值。而在每收到一個對新的報文段的確認後,把擁塞視窗增加至多一個MSS的數值。用這樣的方法逐步增大發送方的擁塞視窗 cwnd ,可以使分組注入到網路的速率更加合理。

每經過一個傳輸輪次,擁塞視窗 cwnd 就加倍。一個傳輸輪次所經歷的時間其實就是往返時間RTT。不過“傳輸輪次”更加強調:把擁塞視窗cwnd所允許傳送的報文段都連續傳送出去,並收到了對已傳送的最後一個位元組的確認。
另,慢開始的“慢”並不是指cwnd的增長速率慢,而是指在TCP開始傳送報文段時先設定cwnd=1,使得傳送方在開始時只發送一個報文段(目的是試探一下網路的擁塞情況),然後再逐漸增大cwnd。

為了防止擁塞視窗cwnd增長過大引起網路擁塞,還需要設定一個慢開始門限ssthresh狀態變數。慢開始門限ssthresh的用法如下:

  • 當 cwnd < ssthresh 時,使用上述的慢開始演算法。

  • 當 cwnd > ssthresh 時,停止使用慢開始演算法而改用擁塞避免演算法。

  • 當 cwnd = ssthresh 時,既可使用慢開始演算法,也可使用擁塞控制避免演算法。

慢啟動為什麼會對拷貝海量小檔案的需求造成重大效能損失?

舉個簡單的例子,我們對每個檔案都採用獨立的TCP連線來傳輸(迴圈使用scp拷貝就是這個例子的實際場景,很常見的用法)。那麼工作過程應該是,每傳輸一個檔案建立一個

連線,然後連線處於慢啟動階段,傳輸小檔案,每個小檔案幾乎都處於獨立連線的慢啟動階段被傳輸,這樣傳輸過程所用的TCP包的總量就會增多。更細緻的說一說這個事,如果在

慢啟動過程中傳輸一個小檔案,我們可能需要2至3個小包,而在一個已經完成慢啟動的TCP通道中(TCP通道已進入在高速傳輸階段),我們傳輸這個檔案可能只需要1個大包。

網路拷貝檔案的時間基本上全部消耗都在網路傳輸的過程中(發資料過去等對端ACK,ACK確認歸來繼續再發,這樣的資料來回互動相比較本機的檔案讀寫非常耗時間),撇開三次

握手和四次握手那些包,如果檔案的數量足夠大,這個總時間就會被放大到需求難以忍受的地步。

因此,在遷移海量小檔案的需求下,我們不能使用“對每個檔案都採用獨立的TCP連線來傳輸(迴圈使用scp拷貝)“這樣的策略,它會使每個檔案的傳輸都處於在一個獨立TCP的慢啟

動階段。

如何避免慢啟動,進而提升效能?

儘量把大量小檔案放在一個TCP連線中排隊傳輸。起初的一兩個檔案處於慢啟動過程傳輸,後續的檔案傳輸全部處於高速通道中傳輸,用這樣的方式來減少發包的數

目,進而降低時間消耗。同樣,實際上這種傳輸策略帶來的效能提升的功勞不僅僅歸於避免慢啟動,事實上也避免了大量的3次握手和四次握手,這個對海量小檔案傳輸的效能消耗

也非常致命。

2、擁塞避免

cwnd不能一直這樣無限增長下去,一定需要某個限制。TCP使用了一個叫慢啟動門限(ssthresh)的變數,一旦cwnd>=ssthresh(大多數TCP的實現,通常大小都是65536),慢

啟動過程結束,擁塞避免階段開始;

擁塞避免:cwnd的值不再指數級往上升,開始加法增加。此時當視窗中所有的報文段都被確認時,cwnd的大小加1,cwnd的值就隨著RTT開始線性增加,這樣就可以避免增長過

快導致網路擁塞,慢慢的增加調整到網路的最佳值。(它邏輯很簡單就是到一定值後,cwnd不在是指數增長,而是+1增長。這樣顯然慢多了)。

非ECN環境下的擁塞判斷,傳送方RTO超時,重傳了一個報文段,它的邏輯如下:

1)把ssthresh降低為cwnd值的一半。

2)把cwnd重新設定為1。

3)重新進入慢啟動過程。

讓擁塞視窗cwnd緩慢地增大,即每經過一個往返時間RTT就把傳送方的擁塞視窗cwnd加1,而不是加倍。這樣擁塞視窗cwnd按線性規律緩慢增長,比慢開始演算法的擁塞視窗增長速率緩慢得多。

無論在慢開始階段還是在擁塞避免階段,只要傳送方判斷網路出現擁塞(其根據就是沒有收到確認),就要把慢開始門限ssthresh設定為出現擁塞時的傳送 方視窗值的一半(但不能小於2)。然後把擁塞視窗cwnd重新設定為1,執行慢開始演算法。

這樣做的目的就是要迅速減少主機發送到網路中的分組數,使得發生 擁塞的路由器有足夠時間把佇列中積壓的分組處理完畢。

如下圖,用具體數值說明了上述擁塞控制的過程。現在傳送視窗的大小和擁塞視窗一樣大。

3、快重傳

快重傳
快重傳演算法首先要求接收方每收到一個失序的報文段後就立即發出重複確認(為的是使傳送方及早知道有報文段沒有到達對方)而不要等到自己傳送資料時才進行捎帶確認。

接收方收到了M1和M2後都分別發出了確認。現在假定接收方沒有收到M3但接著收到了M4。

顯然,接收方不能確認M4,因為M4是收到的失序報文段。根據 可靠傳輸原理,接收方可以什麼都不做,也可以在適當時機發送一次對M2的確認。

但按照快重傳演算法的規定,接收方應及時傳送對M2的重複確認,這樣做可以讓 傳送方及早知道報文段M3沒有到達接收方。傳送方接著傳送了M5和M6。接收方收到這兩個報文後,也還要再次發出對M2的重複確認。這樣,傳送方共收到了 接收方的四個對M2的確認,其中後三個都是重複確認。

快重傳演算法還規定,傳送方只要一連收到三個重複確認就應當立即重傳對方尚未收到的報文段M3,而不必 繼續等待M3設定的重傳計時器到期。

由於傳送方儘早重傳未被確認的報文段,因此採用快重傳後可以使整個網路吞吐量提高約20%。

3.1、超時重傳機制

一種是不回ack,死等3,當傳送方發現收不到3的ack超時後,會重傳3。一旦接收方收到3後,會ack 回 4——意味著3和4都收到了。

但是,這種方式會有比較嚴重的問題,那就是因為要死等3,所以會導致4和5即便已經收到了,而傳送方也完全不知道發生了什麼事,因為沒有收到Ack,所以,傳送方可能會

悲觀地認為也丟了,所以有可能也會導致4和5的重傳。

對此有兩種選擇:

① 一種是僅重傳timeout的包。也就是第3份資料。

② 另一種是重傳timeout後所有的資料,也就是第3,4,5這三份資料。

這兩種方式有好也有不好。第一種會節省頻寬,但是慢,第二種會快一點,但是會浪費頻寬,也可能會有無用功。但總體來說都不好。因為都在等timeout,timeout可能會很長。

3.2、快速重傳機制

於是,TCP引入了一種叫Fast Retransmit的演算法,不以時間驅動,而以資料驅動重傳。也就是說,如果,包沒有連續到達,就ack最後那個可能被丟了的包,如果傳送方連續收到

3次相同的ack,就重傳。Fast Retransmit的好處是不用等timeout了再重傳,而是隻是三次相同的ack就重傳。

比如:如果傳送方發出了1,2,3,4,5份資料,第一份先到送了,於是就ack回2,結果2因為某些原因沒收到,3到達了,於是還是ack回2,後面的4和5都到了,但是還是ack回2

因為2還是沒有收到,於是傳送端收到了三個ack=2的確認,知道了2還沒有到,於是就馬上重轉2。然後,接收端收到了2,此時因為3,4,5都收到了,於是ack回6。示意圖如下

Fast Retransmit只解決了一個問題,就是timeout的問題,它依然面臨一個艱難的選擇,就是重轉之前的一個還是重灌所有的問題。對於上面的示例來說,是重傳#2呢還是重傳

#2,#3,#4,#5呢?因為傳送端並不清楚這連續的3個ack(2)是誰傳回來的?也許傳送端發了20份資料,是#6,#10,#20傳來的呢。這樣,傳送端很有可能要重傳從#2到

#20的這堆資料(這就是某些TCP的實際的實現)。可見,這是一把雙刃劍。

4、快恢復

與快重傳配合使用的還有快恢復演算法,其過程有以下兩個要點:

  • 當傳送方連續收到三個重複確認,就執行“乘法減小”演算法,把慢開始門限ssthresh減半。

  • 與慢開始不同之處是現在不執行慢開始演算法(即擁塞視窗cwnd現在不設定為1),而是把cwnd值設定為 慢開始門限ssthresh減半後的數值,然後開始執行擁塞避免演算法(“加法增大”),使擁塞視窗緩慢地線性增大。

六、參考資料

1、https://www.sohu.com/a/339068354_774177

2、https://blog.csdn.net/u014590757/article/details/80035115

3、TCP/IP詳解卷1:協議