1、概述
眾所周知,TCP/IP是面向鏈接的可靠傳輸協(xié)議,但是問題是如何實現(xiàn)可靠傳輸?shù)哪??在我看來,TCP/IP可靠傳輸?shù)幕A(chǔ)是滑動窗口協(xié)議和連續(xù)ARQ協(xié)議,配合著流量控制和擁塞控制,使得整個傳輸過程保證:
2、滑動窗口協(xié)議和連續(xù)ARQ協(xié)議
2.1、停止等待協(xié)議和自動重傳請求(ARQ)
所謂停止等待協(xié)議就是每發(fā)送完一個分組就停止發(fā)送,等待對方的確認。在收到確認后再發(fā)送下一個分組。但是在傳輸過程中可能出現(xiàn)意外,這時候就需要用到ARQ協(xié)議了,比如說:
2.1.1、B可能沒有收到A發(fā)送的M1M1
這時候A就會有個超時計時器,當超時計時器到期時沒收到B的確認報文,則A重新發(fā)送M1M1,因此必須保證以下幾點:

2.1.2、A沒有收到B的確認報文或確認報文遲到
發(fā)生確認丟失時,B會再一次收到A的重傳分組M1M1,此時B會進行如下行動:
丟棄這個重復(fù)分組M1M1
向A發(fā)送確認報文
發(fā)生確認遲到時,A會再一次收到B的確認報文,這時候A收下并丟棄這個確認報文,并不做什么。

2.2、滑動窗口協(xié)議和連續(xù)ARQ協(xié)議
2.2.1、累積確認方式
為了提高信道的利用率,實際上采用了流水線傳輸?shù)姆桨?。如圖:

這時就需要使用連續(xù)ARQ協(xié)議和滑動窗口協(xié)議。發(fā)送方和接收方各自維持著發(fā)送窗口和接受窗口,發(fā)送方每收到一個確認,就把發(fā)送窗口向前滑動一個分組的位置。接收方一般采用累計確認方式,即接收方不必對收到的分組逐個發(fā)送確認,而是可以在收到幾個分組后,對按序到達的最后一個分組發(fā)送確認,這樣就表示:到這個分組位置的所有分組都已經(jīng)正確收到了。

2.2.2、累積確認方式詳細解析
由圖可見,描述一個發(fā)送窗口的狀態(tài)需要三個指針P1P1、P2P2、P3P3
P3?P1=AP3?P1=A 的發(fā)送窗口(通知窗口)
P2?P1=P2?P1=已發(fā)送但尚未收到確認的字節(jié)數(shù)
P3?P2=P3?P2=允許發(fā)送但尚未發(fā)送的字節(jié)數(shù)(可用窗口或有效窗口)
解析一:此時B沒有收到序號為31的數(shù)據(jù),因此只能對按序收到的數(shù)據(jù)中的最高的序號給出確認,即此時B的確認號還是30(因為B沒有收到序號31的數(shù)據(jù),只能發(fā)送序號30的確認號)

解析二:此時B收到了序號31的數(shù)據(jù),那么B會進行如下處理:
A收到B的確認號后,就可以把發(fā)送窗口向前滑動3個序號,但P2P2指針不變

解析三:A在繼續(xù)發(fā)送完序號42~53的數(shù)據(jù)后,指針P2P2和P3P3重合。發(fā)送窗口內(nèi)的序號都已經(jīng)用完,但還沒有收到確認。由于發(fā)送窗口已滿,可用窗口已減小到了零,因此必須停止發(fā)送。此時A設(shè)置了超時計時器,超時計時器到期時就重傳這部分數(shù)據(jù),重置超時計時器,知道收到B的確認為止。如果A收到的確認號落在發(fā)送窗口內(nèi),那么A就可以使發(fā)送窗口繼續(xù)向前滑動,并發(fā)送新的數(shù)據(jù)。
2.2.3、發(fā)送緩存與發(fā)送窗口、接收緩存與接收窗口
發(fā)送緩存用來暫時存放(即發(fā)送窗口):
接收緩存用來暫時存放:
2.2.4、發(fā)送緩存和接收緩存小結(jié)
A的發(fā)送窗口根據(jù)B的接收窗口設(shè)置,但是二者并以總是一樣大
對于不按序到達的數(shù)據(jù)應(yīng)如何處理,TCP彼岸準并無明確規(guī)定(一般都是臨時保存在接收窗口中,等到字節(jié)流完整接收后再按序提交給上層的應(yīng)用進程)
TCP要求接收方必須有累積確認的功能,這樣子可以減少傳輸開銷

2.2.5、超時重傳時間的確定
由上可知,TCP的發(fā)送方在規(guī)定的時間內(nèi)沒有收到確認就要重傳已發(fā)送的報文段。但是由于TCP的下層互聯(lián)網(wǎng)環(huán)境,發(fā)送的報文段可能只經(jīng)過一個高速率的局域網(wǎng),也可能經(jīng)過多個低速率的網(wǎng)絡(luò),并且每個IP數(shù)據(jù)報所選擇的路由還可能不同,因此注定超時重傳時間要動態(tài)變化。
2.2.5.1、加權(quán)平均往返時間(平滑的往返時間,RTTsRTTs)
TCP采用的一種自適應(yīng)算法,每當?shù)谝淮螠y量到RTT樣本時,RTTsRTTs值就取為所測量到的RTT樣本值。但以后每測量到一個新的RTT樣本,就按下式重新計算一次RTTsRTTs:
新的RTTs=(1?α)?(舊的RTTs)+α?(新的RTT樣本)新的RTTs=(1?α)?(舊的RTTs)+α?(新的RTT樣本)
在上式中,0?α<10?α<1,若α接近零,則表示新的RTTs新的RTTs與舊的RTTs舊的RTTs值相比變化不大;若α接近1,則表示新的RTTs新的RTTs受RTT樣本的影響較大(RTT值更新較快)。α推薦值為1/8,即0.125.
2.2.5.2、超時重傳時間(RTO)
超時計時器設(shè)置的超時重傳時間應(yīng)略大于上面得出的RTTsRTTs,計算公式如下:
RTO=RTTs+4?RTTDRTO=RTTs+4?RTTD
2.2.5.3、RTT的偏差的加權(quán)平均值(RTTDRTTD)
RTTDRTTD與RTTsRTTs和新的RTT樣本之差有關(guān)。當?shù)谝淮螠y量時,RTTDRTTD取值為RTT樣本的一般,在以后的測量中按下式計算,0?β<10?β<1,推薦取值1/4,即0.25:
新的RTTD=(1?β)?(舊的RTTD)+β?|RTTs?新的RTT樣本|新的RTTD=(1?β)?(舊的RTTD)+β?|RTTs?新的RTT樣本|
2.2.5.4、問題
假設(shè)發(fā)送出一個報文段。設(shè)定的重傳時間到了,還沒有收到確認。于是重傳報文段。經(jīng)過了一段時間后,收到了確認報文段。
那么,如何判定收到的確認報文是對先發(fā)送的報文段的確認,還是對后來重傳的報文段的確認?

于是有了Karn算法,即在計算機加權(quán)平均RTTsRTTs時,只要報文段重傳了,就不采用其往返時間樣本。這樣子得出的加權(quán)平均RTTsRTTs和RTO就較準確
但也會引起另外的問題,于是進行修正:報文段每重傳一次,就把超時重傳時間RTO增大一些,典型的做法就是取新的重傳時間為2倍就得重傳時間,當不再發(fā)生報文段的重傳時,才根據(jù)上賣弄的式子計算重傳時間。
3、流量控制
3.1、發(fā)送窗口的確認
鏈接建立時,B根據(jù)自己的接受緩存大小確定窗口值大小,然后告訴A,我的窗口有多大,然后A就根據(jù)B給出的窗口值構(gòu)造自己的發(fā)送窗口(發(fā)送緩存不一定比接受緩存大)。如圖,窗口有前沿和后沿兩個指針,二者都只能前移。

3.2、發(fā)送窗口和接收窗口的同步
但是前沿指針和后沿指針前移不一定是同步的,可能發(fā)生如下情況,關(guān)鍵取決于B告訴A我還能接受多少數(shù)據(jù),于是A就根據(jù)B提供的信息發(fā)送數(shù)據(jù),特別注意發(fā)送方的發(fā)送窗口不能超過接收方給出的額接受窗口的數(shù)值。參考如下圖:

3.3、持續(xù)計時器
假如B向A發(fā)送了零窗口的報文段后不久,B的接收緩存又有了一些存儲控件。于是B向A發(fā)送了rwnd = 400的報文段。然而這個報文段在發(fā)送過程中丟失了。醬紫A就一直等待B發(fā)送的非零窗口的通知,B也一直等待A發(fā)送數(shù)據(jù),導(dǎo)致死鎖。
因此需要一個持續(xù)計時器,當TCP鏈接的一方收到對方的零窗口通知,就啟動持續(xù)計時器。持續(xù)計時器時間到是就發(fā)送一個零窗口探測報文段,而對方就在確認這個探測報文段時給出了現(xiàn)在的窗口值。如果窗口仍為零,那么持續(xù)計時器就重新計時。如果不為零,則可以打破死鎖。
4、擁塞控制
若網(wǎng)絡(luò)中有許多資源同時出現(xiàn)供應(yīng)不足,網(wǎng)絡(luò)性能就要明顯變化,整個網(wǎng)絡(luò)的吞吐量將隨著輸入負荷的增大而下降,這就是擁塞。
擁塞控制就是防止過多的數(shù)據(jù)注入到網(wǎng)絡(luò)中,這樣可以使網(wǎng)絡(luò)中的路由器或鏈路不至于過載。
流量控制往往指點對點的通信量的控制,是一個端到端端額問題。
擁塞控制則是當整個挽留過的輸入負載超過網(wǎng)絡(luò)所能承受的時候,向發(fā)送方發(fā)送控制報文,冰雹蘇發(fā)送端,必須放慢發(fā)送速率。

4.1、慢開始和擁塞避免
發(fā)送方維持一個擁塞窗口(cwnd)的狀態(tài)變量。其大小取決于網(wǎng)絡(luò)的擁塞程度,并且動態(tài)的在變化。發(fā)送方讓自己的發(fā)送窗口小于或等于擁塞窗口。
慢開始的算法思路是:
發(fā)送窗口先設(shè)置cwnd = 1,發(fā)送第一個報文段,以后每收到一個報文段確認,cwnd加1
每經(jīng)過一個傳輸輪次,擁塞窗口cwnd就加倍(即呈指數(shù)增長)
當cwnd大于ssthresh閥值時,改用擁塞避免算法1(加法增大)
假設(shè)增長到某值(如24),網(wǎng)絡(luò)出現(xiàn)超時,此時將ssthresh值變?yōu)橹档囊话?如12)(乘法減小),讓后將cwnd置1,重新采用慢開始算法,重復(fù)如上步驟。
擁塞避免算法的思路是:讓擁塞窗口cwnd線性緩慢增長

4.2、快重傳和快恢復(fù)
快重傳的算法思路是:
快恢復(fù)的算法思路是:

4.3、發(fā)送窗口的上限
也就是說rwnd和cwnd中較小的一個控制發(fā)送方發(fā)送數(shù)據(jù)的速率
發(fā)送窗口的上限值 = Min[rwnd, cwnd]
4.4、隨機早期檢測RED
隨機早期檢測RED將TCP擁塞控制和網(wǎng)絡(luò)層采取的策略聯(lián)系起來。由于網(wǎng)絡(luò)層中路由器的隊列的尾部丟棄策略會影響TCP的擁塞控制,因此需要采用該策略避免網(wǎng)絡(luò)中的全局同步現(xiàn)象。
4.4.1、平均隊列長度LAVLAV
使路由器維持兩個參數(shù),即隊列長度最小門限THminTHmin和最大門限THmaxTHmax,每當一個分組到達時RED組都先計算平均隊列長度LAVLAV,具體算法思路是:
若平均隊列長度小于最小門限THminTHmin,則把新到達的分組放入隊列進行排隊
若平均隊列長度超過最大門限THmaxTHmax,則把新到達的分組丟棄
若平均隊列長度在最小門限THminTHmin和最大門限THmaxTHmax之間,則按照某一概率p將新到達的分組丟棄

平均隊列長度的計算:
平均隊列長度LAV=(1?α)?(舊的RTTs)+α?(新的RTT樣本)平均隊列長度LAV=(1?α)?(舊的RTTs)+α?(新的RTT樣本)
因此可見RED正常工作的關(guān)鍵就是選擇好三個參數(shù):THminTHmin、THmaxTHmax和p
