1. 程式人生 > >TCP協議------可靠性保證機制

TCP協議------可靠性保證機制

        在這篇部落格中介紹了連線管理機制,它是TCP協議保證可靠性的重要機制,除了該機制,還有許多實現可靠性得機制,本文中將一一進行介紹。

1. 確認應答(ACK)機制

在TCP的協議報頭中有兩個欄位:序列號和確認序列號。這兩個欄位就是來保證確認應答機制的。

        傳送方A將要傳送的多個數據段排好序傳送給接收端B。比如說A要傳送序列號為1~1000的資料段。B如果將這些資料全部正確接收了,就會給A傳送一個1001的確認序列號,用於告訴A,它之前傳送的1~1000已經被正確接收,下次從1001開始傳送。如果B只接受到了1~500,此時就會給B傳送501的確認序列號,A收到後會知道500~1000的報文丟失,就會重新發送500~1000的報文段給B。此時就保證了資料的可靠傳輸。

        因為TCP協議是全雙工通訊,雙方都可以作為傳送方和接收方,因此每一方都需要一個序列號和確認序列號來保證資料的可靠傳輸。

        設定序列號同時也可以保證傳送的資料按序到達,如果多個數據段在傳送過程中可能到達的先後順序可能不同,因此可能會導致接受到的資料與傳送時的順序不一致,通過序列號可以保證資料按序到達,也能夠保證資料的可靠性傳輸。

        如果接收端接收到重複的資料段後,也可以通過序列號來進行去重,保證可靠性。

        綜上,序列號和確認序列號的作用有以下幾點:

(1)保證確認應答機制;

(2)保證資料按序到達;

(3)保證去重機制。

2. 超時重傳機制

當主機A向主機B傳送資料報後,一段時間內A沒有收到B的確認訊號,就會進行重傳。造成重傳的原因有兩個:


(1)A向B傳送的資料在傳輸過程中丟失,那麼A再次重傳資料時,就可以保證資料可靠送達;

(2)如果B接收到A的資料了,但B發給A的ACK確認訊號在傳輸過程中丟包了,此時,A再次重傳時,B就會接收到重複的資料,此時B就可以根據報文中的序列號進行去重,保證資料的可靠性傳輸。

        超時重傳的時間如何設定呢?

        如果時間設定的太長,當資料報丟失時,就會影響重傳的效率;如果時間設定的太短,當ACK包延遲時,就會重傳大量的資料包。所以這個時間最好是能保證ACK一定能到達的最短時間。

        TCP協議通過動態計算這個超時重傳的時間。

        在Linux中,超時重傳的時間間隔是500ms的2^n倍(n = 0,1,...)。如果第一次傳送資料報之後,500ms內沒有收到ACK確認,則進行重傳;然後在2*500ms內沒有收到ACK確認,再次進行重傳;再等4*500ms,還沒收到確認,再次進行重傳;...當重傳的次數超過一定的上限後,TCP會認為此時的網路或對方的連接出現異常,會強制關閉連線。

        因此,在進行資料傳輸時,主機A在傳送完資料報之後,會先設定一個鬧鐘,如果在鬧鐘沒響之前ACK報達到,此時取消鬧鐘,進行後續的資料傳輸;如果鬧鐘超時了,ACK報還未到達,此時A就會重傳資料,並重新設定鬧鐘為新的值。

3. 流量控制

        如果傳送端傳送資料的速度過快,導致接收端的接受緩衝區被佔滿了。此時,傳送端在傳送資料時,接收端就不能接收,從而造成丟包,然後傳送端會再次重傳,造成資源等浪費問題。

        在TCP協議的報頭中有一欄位“視窗大小”,它就是接收端用來填寫自己可接收緩衝區的大小的。在客戶端和伺服器端建立三次握手期間會在向對方傳送的ACK報文中填寫自己的可接收緩衝區大小。當雙方開始通訊後,傳送端A向接收端B傳送完資料之後,B會向A傳送ACK確認報,此時可以將B的新的視窗大小放置在ACK包中告訴A自己的接收能力。同理,A也可通過該方法告訴自己的接收能力(視窗大小)。

        所以,接收端可以將自己的接收緩衝區還能接收多少資料的大小(視窗大小)告訴傳送端,傳送端根據這個值來控制自己傳送的速度,如果視窗比較小時,就減緩傳送的速度。如果接收端的可接受緩衝區大小為0,此時,傳送端就停止傳送資料。當接收端的視窗大小不為0時,要向傳送端傳送一個視窗更新的通知,使傳送端再次開始傳送資料。如果一段時間(超時重發的時間)後,傳送端還沒有收到接收端視窗更新的通知,就會向接收端傳送一個視窗探測的資料報(該報文中的PSH標誌位為1),然後,接收端會將此時自己的視窗大小告訴傳送端。如果視窗更新的報文丟失,傳送端就會一直髮送視窗探測的資料報。

        在上述中,TCP通過接收端的接收能力來控制傳送端的傳送速度,就叫做流量控制。視窗越大,網路的吞吐量越高。

    在TCP報頭中的視窗大小佔16位,可以表示的最大數字是2^16即65535,它以位元組為單位,所以視窗大小最大為64KB,也就是說接收緩衝區的大小最大為64KB,但是實際的可接收緩衝區大小不能這麼小。因此在TCP報頭的40位元組選項中還有一視窗擴大因子M,所以視窗的實際大小為視窗欄位的值左移M位。

4. 滑動視窗

在確認應答機制中,如果傳送端A向接收端B傳送一個數據報後,在等待B的應答之後再發送下一個資料報。如果雙方資料傳輸的時間過長,A等待的時間就過長,此時資料的傳輸效率就會變低。如果A先發送一個數據段1之後,在等待資料段1的時間裡繼續傳送資料段2,在等待資料段1的同時也在等待資料段2的應答,資料段3等,此時就會將各資料段的等待時間重疊起來,這樣便可以提高資料傳輸的效率。

        但是,A一次傳送多少個數據段呢?由上述的視窗大小可以知道接收端的接收能力,所以可以傳送接收端的視窗大小的資料段。比如,B的視窗大小是4000,一個數據段的大小是1000,因此A可以一次傳送四個資料段(1,2,3,4),當收到資料段1的應答之後,滑動視窗後移,A再發送資料段5。依次往後。

        作業系統為了維護這個滑動視窗,在傳送端開闢了一個傳送緩衝區。將待發送的資料放在傳送緩衝區中,如果滑動視窗中的資料表示已傳送但是還沒收到應答的資料,當收到一個數據段的應答後,將該資料段從傳送緩衝區中刪除,然後滑動視窗後移,傳送新的資料段。

5. 快速重傳機制

如果上述中多個數據段1:0~1000;2:1001~2000;3:2001~3000;4:3001~4000,由A同時傳送給B時,會出現以下兩種丟包情況:

(1)應答資料段ACK丟包了。如果資料段1的應答ACK丟失了,但資料段2,3,4的應答ACK沒有丟失,因為資料段4的應答ACK中的確認序號為4001,表明B將資料段1,2,3,4都已經接收到了,此時就可以忽略資料段1的應答ACK丟失問題了。如果資料段4的確認ACK丟失了,並且後面沒有傳送更大序列號的報文段,此時就會啟動超時重傳機制,重發資料段4。如果資料段1,2,3,4的應答ACK都丟失了,此時也會啟動超時重傳機制,進行重新發送。

(2)資料段丟包了。比如資料段1丟包了,但是2,3,4沒有丟,所以B在對A資料段2,3,4的確認報中都會使確認序號置為0。表明B要求重發資料段1,當B接收到A重發後的資料段1後,會將確認序號置為4001,因為4001之前的資料段B都收到了並將它們放到了接收緩衝區中。

在上述資料段1丟包時,如果A連續三次收到確認序號為0的ACK應答,此時就會將資料段1進行重傳。而此時可能還沒有到達資料段1的超時重傳時間。這種機制就被稱為“快速重傳機制”(快重傳)

        超時重傳機制是基本的保證,快重傳機制是基於其之上的。當所有的資料報都丟失之後或所有的ACK應答報都丟失之後,就會啟動超時重傳機制。

        綜上所述,我們可以知道TCP協議報頭中的視窗有以下作用:

(1)可以指示滑動視窗大小

(2)可以控制傳送端的傳送速度。

6. 擁塞控制

        如果TCP的剛啟動時就傳送大量資料到網路中,此時並不知道網路的擁塞狀態如何。如果此時網路特別擁塞就會造成大量的丟包問題。因此TCP採用“慢啟動”機制。即剛開始傳送少量的資料到網路中,如果網路狀態良好,再增大發送資料的速度。那麼,慢啟動時要傳送多少資料到網路中,之後又要傳送多少資料呢?這裡引入擁塞視窗的概念。

        傳送方要維持一個擁塞視窗的變數。擁塞視窗的大小根據網路的擁塞狀況在動態的變化。傳送方使自己的傳送視窗大小等於擁塞視窗的大小與接收端接收視窗的較小值。即此時既要考慮網路的擁塞狀況,又要考慮對方的接收能力大小。如果沒有出現網路擁塞,擁塞視窗就大一點,如果出現了網路擁塞,擁塞視窗就減小。

慢啟動機制為:

最初設定擁塞視窗為1,當接收到一個ACK應答之後,擁塞視窗加1。根據擁塞視窗和接收方的接收能力來決定傳送資料的多少。

雖然最初擁塞視窗大小為1,但是因為它是呈指數增長的,之後會越來越大(此時為慢啟動演算法)。因此傳送到網路中的資料會越來越多,造成網路擁塞的概率也會越來越大。

所以,不能使擁塞視窗無限制的增長下去。因此,這裡引入一個慢啟動的閾值(當TCP啟動時,慢啟動閾值等於視窗最大值),當擁塞視窗到達這個閾值時,就使擁塞視窗呈線性增長,一次加1(此時為避免擁塞演算法)。

無論在慢啟動階段還是在避免擁塞階段,當引起網路擁塞時,慢啟動閾值減小為發生網路擁塞時擁塞視窗的一半,同時擁塞視窗減小為1,再從1開始慢啟動增長。(當發生少量的丟包時,我們僅僅觸發超時重傳機制,當發生大量的丟包時,就認為發生了網路擁塞,此時就要改變慢啟動閾值和擁塞視窗了)。

        如下圖所示:


擁塞控制,是傳送方使自己的傳送視窗大小等於擁塞視窗與接收端接收視窗的較小值。即此時既要考慮網路的擁塞狀況,又要考慮對方的接收能力大小。

7. 延遲應答

如果接收端B的視窗大小是1M,此時傳送端A向B傳送了500K的資料,如果B接收到資料之後立即發出響應,此時ACK報文中的視窗大小即為500K。

        如果B處理資料的速度很快比如在很短的時間內就將500K的資料處理完了。並且B的處理能力還未到達上限,即給B更多的資料B也能很快處理完。此時,B可以延遲一會,等500K的資料處理完之後,在進行應答,此時ACK報文中的視窗值即為1M。這樣A下一次就可以傳送更多資料交給B處理。從而提高效率。

        因為視窗越大,網路的吞吐量越大,資料的傳輸效率就越高。所以要在網路不擁塞的情況下儘可能的提高傳輸效率。

        但是,也不能一直延遲下去,這裡有兩個限制:

(1)數量限制:每個N個包就應答一次(N一般為2);

(2)時間限制:超過最大延遲時間就應答一次(最大延遲時間一般為200ms)。

8. 捎帶應答

當主機A給主機B傳輸資料後,B會向A發出ACK響應報文,之後B可能還會向A傳送資料報文,此時,可以將B要給A傳送的資料資訊搭載在ACK報文上,一起傳送給A,這樣就可以減少一次的報文傳送,從而提高了效率。

        綜上所述,TCP協議既要保證可靠性傳輸,又要提高效能。所以它比較複雜。

可靠性保證為:

    校驗和,序列號,連線管理機制,確認應答機制,超時重傳機制,流量控制,擁塞控制

提高效能的機制:

    滑動視窗,快重傳機制,延遲應答機制,捎帶應答機制。

9. 粘包問題

當資料傳輸到TCP傳輸層時,可以根據序列號將資料按序排放在接收緩衝中。當應用層從緩衝區中讀取資料時,應用層看到的是一串串的位元組流。那麼從哪一部分開始,到哪一部分結束是一個完整的應用層資料包呢?如果相對於完整的資料包,應用層在多讀或少讀資料後就會形成粘包問題。(此時的包是應用層的資料包)

        因此,在應用層讀取資料時,要明確兩個包之間的界限。

(1)對應定長的資料報,應用層雙發可以提前協商好。比如傳送端傳送資料時一個包的長度為int大小,接收端在接收時也接受一個int大小的資料報;

(2)對於變長的資料報。可以在資料報的頭部加上一個資料包長的欄位,應用層在讀取時可以根據該欄位來判斷資料報的長度;

(3)對於變長的資料報。還可以在一個數據報的結尾加上一個分隔字元來區分如HTTP協議中的\n,這是由應用層協議來制定的。

        對於UDP來說,如果資料沒有交付到上層,UDP協議報頭中的資料報長還存在,因此可以根據該欄位來讀取一個報文的長度。同時UDP是一個一個報文交付到上層的,本身就有明確的邊界,而應用層在接收UDP報文時要麼完整的收,要麼不收,因此不會出現粘包問題。

10. TCP的異常情況

程序終止:程序終止時會關閉檔案描述符,仍然可以發FIN,和正常終止沒有區別;

機器重啟:和程序終止情況相同;

機器斷電或網線斷開:A,B兩端建立連線後,B端因為斷電導致連線斷開,此時A端並不知道B端的連線已經斷開。當它向B端進行寫入操作時,發現B端的連線已不存在,所以會發送RST重新建立連線;即使A端沒有進行寫入操作,TCP也內建了一個保活定時器,定期檢查對端的連線狀態,一旦對端的而連線不在,本端的連線也會斷開。