(二十三)運輸層--TCP可靠傳輸的實現
TCP可靠傳輸的實現
這篇文章我們來學習TCP可靠傳輸的實現。
為了方便討論,我們假定資料傳輸只在一個方向進行,即A傳送資料,B給出確認。這樣的好處是使討論限於兩個視窗,即傳送方A的傳送視窗和接收方B的接收視窗。
以位元組為單位的滑動視窗
TCP的滑動視窗是以位元組為單位的。現假定A收到了B發來的確認報文段,其中視窗是10位元組(B的接收視窗是10位元組),而確認號是28(表明B期望收到的下一個序號是28,而序號28為止的資料已收到了)。根據這兩個資料,A就構造出自己的傳送視窗,如下圖所示:
先討論傳送方A的傳送視窗。傳送視窗表示:在沒有收到B的確認的情況下,A可以連續把視窗內的資料都發送出去。凡是已經發送過的資料,在未收到確認之前都必須暫時保留,以便在超時重傳時使用。傳送窗口裡面的序號表示允許傳送的序號。顯然,視窗越大,傳送方就可以在收到對方確認之前連續傳送更多的資料,因而可能獲得更高的傳輸效率。A的傳送視窗一定不能超過B的接收視窗數值(傳送方的傳送視窗大小還要受到當時網路擁塞程度的制約,但目前,暫不考慮)。
傳送視窗後沿的後面部分表示已傳送且已收到了確認,這些資料顯然不需要再保留了。傳送視窗前沿的前面部分表示不允許傳送的,因為接收方都沒有為這部分資料保留臨時存放的快取空間。
傳送視窗的位置由視窗前沿和後沿的位置共同確定。傳送視窗後沿的變化情況有兩種可能,即不動(沒有收到新的確認)和前移(收到了新的確認)。傳送視窗後沿不可能向後移動,因為不能撤銷掉已收到的確認。傳送視窗前沿通常是不斷向前移動,但也有可能不動(兩種情況,一是沒有收到新的確認,傳送視窗的大小不變;二是收到了新的確認但對方通知的視窗縮小了,使得傳送視窗前沿正好不動)。
現在假定A傳送了序號為28~34的資料。這時,傳送視窗位置並未改變,但傳送視窗內靠後面有7個位元組表示已傳送但未收到確認。而傳送視窗內靠前面的3個位元組是允許傳送但尚未傳送的。
要描述一個傳送視窗的狀態需要三個指標:P1, P2, P3。指標都指向位元組的序號,意義如下:
(1)小於P1的是已傳送並已收到確認的部分,大於P3的是不允許傳送的
(2)P3 - P1為A的傳送視窗
(3)P2 - P1為已傳送但尚未收到確認的位元組數
(4)P3 - P2為允許傳送但當前尚未傳送的位元組數(又稱為可用視窗或有效視窗)
再看一下B的接收視窗。B的接收視窗大小是10。在接收視窗外面,到28號為止的資料是已經發送過確認,並且已經交付主機了。因此B可以不再保留這些資料。接收視窗內的序號(28~37)是允許接收的。在下圖中,B收到了序號為29和30的資料。這些資料沒有按序到達,因為序號為28的資料沒有收到(也許丟失了,也許滯留在網路中的某處)。請注意,B只能對按序收到的資料中的最高序號給出確認,因此B傳送的確認報文段中的確認號仍然是28,而不是29或30。
現在假定B收到了序號為28的資料,並把序號為28~30的資料交付主機,然後B刪除這些資料,接著把接收視窗向前移動3個序號,同時給A傳送確認,其中視窗值仍為10,但確認號是31。這表明B已經收到了序號31為止的資料。此時B還收到了序號為32, 33的資料,但這些都沒有按序到達,只能先暫存在接收視窗中。A收到B的確認後,就可以把傳送視窗向前滑動3個序號,但指標P2不動。可以看出,現在A的可用視窗增大了,可傳送的序號範圍是35~40。
如下圖所示,A在繼續傳送完序號35~40的資料後,指標P2向前移動和P3重合。傳送視窗內的序號都已用完,但還沒有收到確認。由於A的可用視窗減小到0,因此必須停止傳送。A在經過一段時間後(由超時計時器控制),就重傳這部分資料,重新設定計時器,直到收到B的確認為止。如果A收到確認號落在傳送視窗內,那麼A就可以使傳送視窗繼續向前滑動,併發送新的資料。請注意,在沒有收到B的確認時,為了保證可靠傳輸,A只能認為B還沒有收到這些資料。
前文說過,傳送方的應用程序把位元組流寫入TCP的傳送快取,接收方的應用程序從TCP的接收快取中讀取位元組流。下面進一步討論視窗和快取的關係。
如下圖所示,畫出了傳送方維持的傳送快取和傳送視窗:
傳送快取用來暫時存放:
(1)傳送應用程式傳送給傳送方TCP準備傳送的資料
(2)TCP已傳送但尚未收到確認的資料
傳送視窗通常只是傳送快取的一部分。已被確認的資料應當從傳送快取中刪除,因此傳送快取和傳送視窗的後沿是重合的。傳送應用程式最後寫入傳送快取的位元組減去最後被確認的位元組,就是還保留在傳送快取中的被寫入的位元組數。傳送應用程式必須控制寫入快取的速率,不能太快,否則傳送快取就會沒有存放資料的空間。
如下圖所示,畫出了接收方維持的接收快取和接收視窗:
接收快取用來暫時存放:
(1)按序到達的,但尚未被接收應用程式讀取的資料
(2)未按序到達的資料
如果收到的分組被檢測出有差錯,則要丟棄。如果接收應用程式來不及讀取收到的資料,接收快取最終就會被填滿,使接收視窗減小到0。反之,如果接收應用程式能夠及時從接收快取中讀取收到的資料,接收視窗就可以增大,但最大不能超過接收快取的大小。
根據以上的討論,強調以下三點:
(1)雖然A的傳送視窗是根據B的接收視窗設定的,但在同一時刻,A的傳送視窗並不總是和B的接收視窗一樣大。這是因為通過網路傳送視窗值需要經歷一定的時間滯後,傳送方A還可能根據網路當時的擁塞情況適當減小自己的傳送視窗數值
(2)對於不按序到達的資料應如何處理,TCP標準並無明確規定。如果接收方把不按序到達的資料一律丟棄,那麼接收視窗的管理將會比較簡單,但這樣做對網路資源的利用不利,因為傳送方會重複傳送較多的資料。因此TCP通常對不按序到達的資料是先臨時存放在接收視窗中,等到位元組流中所缺少的位元組收到後,再按序交付上層的應用程序。
(3)TCP要求接收方必須有累計確認的功能,這樣可以減小傳輸開銷。接收方可以在合適的時候傳送確認,也可以在自己有資料要傳送時把確認資訊順便捎帶上。但注意兩點,一是接收方不應過分推遲傳送確認,否則會導致傳送方不必要的重傳,這反而浪費了網路的資源。TCP標準規定,確認推遲的時間不應超過0.5秒。若收到一連串具有最大長度的報文段,則必須每隔一個報文段就傳送一個確認。二是捎帶確認實際上並不經常發生,因為大多數應用程式很少同時在兩個方向上傳送資料。