1. 程式人生 > >計算機網路學習五:傳輸層

計算機網路學習五:傳輸層

1 傳輸層概述

(1) 作用

為分組交換網上的不同主機的不同程序提供通訊服務。在OSI七層參考模型中,傳輸層是面向通訊的最高層,也是使用者功能的最底層。

(2) 傳輸層兩大重要的功能

複用:在傳送端,多個應用程序共用一個傳輸層;

分用:在接收端,傳輸層會根據埠號將資料分派給不同的應用程序。

(3) 傳輸層和網路層的區別

網路層為不同主機提供通訊服務,而傳輸層為不同主機的不同應用提供通訊服務。

網路層只對報文頭部進行差錯檢測,而傳輸層對整個報文進行差錯檢測。

(4) 傳輸層協議

因特網為應用層提供了兩種截然不同的傳輸層協議,一種是UDP(使用者資料報協議),它為呼叫它的應用程式提供了一種不可靠、無連線的服務。另一種是TCP(傳輸控制協議),它為呼叫它的應用程式提供了一種可靠的、面向連線的服務。

UDP和TCP最基本的責任是,將兩個端系統間IP的交付服務擴充套件為執行在端系統上的兩個程序之間的交付服務;UDP和TCP還在其報文段首部中包含了差錯檢查欄位而提供完整性檢查;另外,UDP是一種無連線的、不可靠的服務,而TCP提供了可靠的資料傳輸,它通過使用流量控制、序號、確認和定時器,確保正確地、按序地將資料從傳送程序交付給接收程序。除此之外,TCP還提供了擁塞控制。

2 UDP(使用者資料報協議)詳解

2.1 UDP的特點

(1) UDP只在IP資料報服務的基礎上增加了少量的功能:複用、分用和對整個報文的差錯檢測。

(2) UDP是無連線的:通訊前不需要建立連線,通訊結束也無需釋放連線。

(3) UDP是不可靠的:它是盡力而為交付,不能確保每一個數據報都送達。

(4) UDP是面向報文的:所謂面向報文就是指,UDP資料傳輸的單位是報文,且不會對資料作任何拆分和拼接 操作。

(a) 在傳送端,應用程式給傳輸層的UDP什麼樣的資料,UDP不會對資料進行切分,只增加一個UDP頭並交給網路層。

(b) 在接收端,UDP收到網路層的資料報後,去除IP資料報頭部後遍交給應用層,不會作任何拼接操作。

(5) UDP沒有擁塞控制:UDP始終以恆定的速率傳送資料,並不會根據網路擁塞情況對傳送速率作調整。這種方式有利有弊。

(a) 弊端:網路擁塞時有些報文可能會丟失,因此UDP不可靠。

(b) 優點:有些使用場景允許報文丟失,如:直播、語音通話,但對實時性要求很高,此時UDP還是很有用武之地的。

(6) UDP支援一對一、一對多、多對多、多對一通訊。而TCP只支援一對一通訊。

(7) UDP首部開銷小,只有8位元組。而TCP頭部至少由20位元組,相比於TCP要高效很多。

2.2 UDP報文頭

頭部結構中各部分的作用:

(1) 16位源埠號

記錄源埠號,在需要對方回信時選用。不需要時可用全0。

(2) 16位目的埠號

記錄目標埠號。這在終點交付報文時必須要使用到。

(3) 長度

UDP資料報的長度(包括資料和首部),其最小值為8B(即僅有首部沒有資料的情況)。

(4) 校驗和

檢測UDP資料報在傳輸中是否有錯,有錯就丟棄。該欄位時可選的,當源主機不想計算校驗和,則直接令該欄位為全0。當傳輸層從IP層收到UDP資料報時,就根據首部中的目的埠,把UDP資料報通過相應的埠,上交給程序。如果接收方UDP發現收到的報文中目的埠號不正確(即不存在對應埠號的應用程序),就丟棄該報文,並由ICMP傳送“埠不可達”差錯報文交給傳送方。

3 TCP(傳輸控制協議)詳解

3.1 TCP特點

(1) TCP是面向連線的

通訊前需要建立連線,通訊結束需要釋放連線。

(2) TCP提供可靠交付服務

所謂可靠指的是:TCP傳送的資料無重複、無丟失、無錯誤、與傳送端順序一致。

(3) TCP是面向位元組流的

所謂面向位元組流指的是:TCP以位元組為單位。雖然傳輸的過程中資料被劃分成一個個資料報,但這只是為了方便傳輸,接收端最終接受到的資料將與傳送端的資料一模一樣。

(4) TCP提供全雙工通訊

所謂全雙工通訊指的是:TCP的兩端既可以作為傳送端,也可以作為接收端。TCP允許通訊雙方的應用程序在任何時候都能傳送資料。TCP連線的兩端都設有傳送快取和接收快取,用來臨時存放雙向通訊的資料。在傳送時,應用程式在把資料傳送給TCP快取後,就可以做自己的事情,而TCP在合適的時候把資料傳送出去。在接收時,TCP把收到的資料放入快取,上層的應用程序在合適的時候讀取快取中的資料。

(5) 一條TCP連線的兩端只能有兩個端點

TCP只能提供點到點的通訊(只支援單播,不提供多播和組播服務),而UDP可以任意方式的通訊。

3.2 TCP連線與套接字

(1) TCP連線是一種抽象的概念,表示一條可以通訊的鏈路。

每條TCP連線有且僅有兩個端點,表示通訊的雙方。且雙方在任意時刻都可以作為傳送者和接收者。

(2) 一條TCP連線的兩端就是兩個套接字。

套接字 = IP地址:埠號。

因此,TCP連線=(套接字1,套接字2)=(IP1:埠號1,IP2:埠號2)

3.3 TCP頭部

TCP頭部長度有20位元組的固定部分,選項部分長度不定,但最多40位元組,因此TCP頭部在20-60位元組之間。

(1) 源埠 和 目的埠

各佔2個位元組,傳輸層和網路層一大重要區別就是傳輸層指定了資料報發往的應用程序,因此需要埠號標識。

(2) 序號

佔4個位元組,當前TCP資料報資料部分的第一個位元組的序號。我們知道,TCP是面向位元組的,它會對傳送的每一個位元組進行編號,而且不同資料報之間是連續編號的。

由於本欄位4位元組,可以給[0,2^32-1]個位元組進行編號(大約4G),而且序號迴圈使用,當傳送完2^32-1個位元組後,序號又從0開始。一般來說,當2^32-1個位元組被髮送的時候,前面的位元組早就傳送成功了,因此序號可以迴圈使用。

(3) 確認號

佔4位元組,表示當前主機作為接收端時,期望接收的下一個位元組的編號是多少。也表示,當前主機已經正確接收的最後一個位元組序號+1。

(4) 資料偏移(報文長度)

佔4位,它表明了資料報頭部的長度。

(5) 保留欄位

佔6位,保留為今後使用,目前置為0。

(6) 識別符號

TCP有6種識別符號,用於表示TCP報文的性質。它們只能為0或1。

(a) URG=1

當URG欄位被置1,表示本資料報的資料部分包含緊急資訊,此時緊急指標有效。

緊急資料一定位於當前資料包資料部分的最前面,緊急指標標明瞭緊急資料的尾部。

如control+c:這個命令要求作業系統立即停止當前程序。此時,這條命令就會存放在資料包資料部分的開頭,並由緊急指標標識命令的位置,並URG欄位被置1。

(b) ACK=1

ACK被置1後確認號欄位才有效。

此外,TCP規定,在連線建立後傳送的所有報文段都必須把ACK置1。

(c) PSH=1

當接收方收到PSH=1的報文後,會立即將資料交付給應用程式,而不會等到緩衝區滿後再提交。

一些互動式應用需要這樣的功能,降低命令的響應時間。

(d) RST=1

當該值為1時,表示當前TCP連接出現嚴重問題,必須要釋放重連。

(e) SYN=1

SYN在建立連線時使用。

當SYN=1,ACK=0時,表示當前報文段是一個連線請求報文。

當SYN=1,ACK=1時,表示當前報文段是一個同意建立連線的應答報文。

(f) FIN=1

FIN=1表示此報文段是一個釋放連線的請求報文。

(7) 接收視窗大小

佔2個位元組,該欄位用於實現TCP的流量控制。

它表示當前接收方的接收視窗的剩餘容量,傳送方收到該值後會將傳送視窗調整成該值的大小。傳送視窗的大小又決定了傳送速率,所以接收方通過設定該值就可以控制傳送放的傳送速率。

傳送方每收到一個數據報都要調整當前的傳送視窗。

(8) 檢驗和

佔2位元組,用於接收端檢驗整個資料包在傳輸過程中是否出錯。

(9) 緊急指標

佔2個位元組,用於標識緊急資料的尾部。

(10) 選項欄位

上述欄位都是每個TCP頭部必須要有的,而選項欄位是可選的,且長度可變,最長40位元組。

最常用的選項欄位為MMS:最大報文長度。

4 TCP傳輸連線管理

TCP在傳輸之前會進行三次溝通,一般稱為“三次握手”,傳完資料斷開的時候要進行四次溝通,一般稱為“四次揮手”。

4.1 TCP三次握手(連線建立)

起初,伺服器和客戶端都為CLOSED狀態。在通訊開始前,雙方都得建立各自的傳輸控制(TCB)。 伺服器建立完TCB後遍進入LISTEN狀態,此時準備接收客戶端發來的連線請求。

(1) 第一次握手

客戶端向服務端傳送連線請求報文段。該報文段的頭部中SYN=1,ACK=0,seq=x。請求傳送後,客戶端便進入SYN-SENT狀態。

注:

SYN=1,ACK=0 表示該報文段為連線請求報文。

x為本次TCP通訊的位元組流的初始序號。

TCP規定:SYN=1的報文段不能有資料部分,但要消耗掉一個序號。

(2) 第二次握手

服務端收到連線請求報文段後,如果同意連線,則會發送一個應答:SYN=1,ACK=1,seq=y,ack=x+1。

該應答傳送完成後伺服器便進入SYN-RCVD狀態。

注:

SYN=1,ACK=1表示該報文段為連線同意的應答報文。

seq=y表示服務端作為傳送者時,傳送位元組流的初始序號。

ack=x+1表示服務端希望下一個資料報傳送序號從x+1開始的位元組。

(3) 第三次握手

當客戶端收到連線同意的應答後,還要向服務端傳送一個確認報文段,表示:服務端發來的連線同意應答已經成功收到。

該報文段的頭部為:ACK=1,seq=x+1,ack=y+1。TCP的標準規定,ACK報文段可以攜帶資料。但如果不攜帶資料則不消耗序號,在這種情況下,下一個資料報文段序號仍是 seq=x+1。

客戶端發完這個報文段後便進入ESTABLISHED狀態,服務端收到這個應答後也進入ESTABLISHED狀態,此時連線的建立完成!

4.2 TCP四次揮手(連線釋放)

TCP連線的釋放一共需要四步,因此稱為四次揮手。

我們知道,TCP連線是雙向的,因此在四次揮手中,前兩次揮手用於斷開一個方向的連線,後兩次揮手用於斷開另一方向的連線。

(1) 第一次揮手

若A認為資料傳送完成,則它需要向B傳送連線釋放請求。該請求只有報文頭,頭中攜帶的主要引數為:

FIN=1,seq=u。此時,A將進入FIN-WAIT-1狀態。

注:

FIN=1表示該報文段是一個連線釋放請求。

seq=u,u-1是A向B傳送的最後一個位元組的序號。

(2) 第二次揮手

B收到連線釋放請求後,會通知相應的應用程式,告訴它A向B這個方向的連線已經釋放。此時B進入CLOSE-WAIT狀態,並向A傳送連線釋放的應答,其報文頭包含:

ACK=1,seq=v,ack=u+1。

注:

ACK=1:除TCP連線請求報文段以外,TCP通訊過程中所有資料報的ACK都為1,表示應答。

seq=v,v-1是B向A傳送的最後一個位元組的序號。

ack=u+1表示希望收到從第u+1個位元組開始的報文段,並且已經成功接收了前u個位元組。

A收到該應答,進入FIN-WAIT-2狀態,等待B傳送連線釋放請求。

第二次揮手完成後,A到B方向的連線已經釋放,B不會再接收資料,A也不會再發送資料。但B到A方向的連線仍然存在,B可以繼續向A傳送資料。

(3) 第三次揮手

當B向A發完所有資料後,向A傳送連線釋放請求,請求頭:FIN=1,ACK=1,seq=w,ack=u+1。B便進入LAST-ACK狀態。

(4) 第四次揮手

A收到釋放請求後,向B傳送確認應答,此時A進入TIME-WAIT狀態。該狀態會持續2MSL(Maximum Segment Lifetime,報文最大生存時間)時間,若該時間段內沒有B的重發請求的話,就進入CLOSED狀態,撤銷TCB。當B收到確認應答後,也便進入CLOSED狀態,撤銷TCB。我們注意到B結束TCP連線的時間要比A早一些。

注:

B只要收到了A發出的確認,就進入CLOSED狀態。同樣,B在撤銷相應的傳輸控制塊TCB後,就結束了這次連線。

4.3 原理詳解

(1) 為什麼連線建立需要三次握手,而不是兩次握手的原因?

防止失效的連線請求報文段被服務端接收,從而產生錯誤。

所謂“已失效的連線請求報文段”是這樣產生的。考慮一種正常情況。A發出連線請求,但因連線請求丟失而未收到確認。於是A再次重傳一次連線請求。後來收到了確認建立了連線。資料傳輸完畢後,就釋放了連線。A共傳送了兩個連線請求的報文段,其中第一個丟失,第二個到達了B。沒有“已失效的連線請求報文段”。

現假定出現一種異常情況,即A發出的第一個連線請求報文段並沒有丟失,而是在某些網路節點長時間滯留了,以致延誤到連線釋放以後的某個時間才到B。本來這是一個已失效的報文段。但是B收到此失效的連線請求報文段後,就誤認為是A又發出一次新的連線請求。於是就向A發出確認報文段,同意建立連線。假定不採用三次握手,那麼只要B發出確認,新的連線就建立了。

由於現在A並沒有發出建立連線的請求,因此不會理睬B的確認,也不會向B傳送資料。但B卻以為新的運輸連線已經建立了,並一直等待A發來資料。B的許多資源就這樣白白浪費了。

採用三次握手的辦法可以防止上述現象的發生。例如在剛才的情況下,A不會向B的確認發出確認。B由於收不到確認,就知道A並沒有要求建立連線。

(2) 為什麼A要先進入TIME-WAIT狀態,等待2MSL時間後才進入CLOSED狀態?

(a) 為了保證客戶端傳送的最後一個ACK報文段能夠達到伺服器。 這個ACK報文段可能丟失,因而使處在LAST-ACK狀態的伺服器收不到確認。伺服器會超時重傳FIN+ACK報文段,客戶端就能在2MSL時間內收到這個重傳的FIN+ACK報文段,接著客戶端重傳一次確認,重啟計時器。最後,客戶端和伺服器都正常進入到CLOSED狀態。如果客戶端在TIME-WAIT狀態不等待一段時間,而是再發送完ACK報文後立即釋放連線,那麼就無法收到伺服器重傳的FIN+ACK報文段,因而也不會再發送一次確認報文。這樣,伺服器就無法按照正常步驟進入CLOSED狀態。

(b) 防止已失效的連線請求報文段出現在本連線中。客戶端在傳送完最後一個ACK確認報文段後,再經過時間2MSL,就可以使本連線持續的時間內所產生的所有報文段都從網路中消失。這樣就可以使下一個新的連線中不會出現這種舊的連線請求報文段。

(3) 為什麼連線的時候是三次握手,關閉的時候卻是四次握手?

因為當Server端收到Client端的SYN連線請求報文後,可以直接傳送SYN+ACK報文。其中ACK報文是用來應答的,SYN報文是用來同步的。但是關閉連線時,當Server端收到FIN報文時,很可能並不會立即關閉SOCKET,所以只能先回復一個ACK報文,告訴Client端,"你發的FIN報文我收到了"。只有等到我Server端所有的報文都發送完了,我才能傳送FIN報文,因此不能一起傳送。故需要四步握手。

(4) 在TIME_WAIT狀態中,如果TCP client端最後一次傳送的ACK丟失了,它將重新發送TIME_WAIT狀態中所需要的時間是依賴於實現方法的。典型的值為30秒、1分鐘和2分鐘。等待之後連線正式關閉,並且所有的資源(包括埠號)都被釋放。

(5) 為什麼有保活時間(長連線)?

另外主機B存在一個保活狀態,即如果主機A突然故障宕機了,那主機2那邊的連線資源什麼時候能釋放呢? 就是保活時間到了後,主機B會發送探測資訊, 以決定是否釋放連線。

5 TCP可靠傳輸的原理

理想的傳輸條件有以下兩個特點:

(1) 傳輸通道不產生差錯。

(2) 不管傳送方以多快的速度傳送資料,接收方總是來得及處理收到的資料。

在這樣的理想傳輸條件下,不需要採取任何措施就能夠實現可靠傳輸。

然而實際的網路都不具備以上兩個理想條件。但我們可以使用一些可靠傳輸協議,當出現差錯時讓傳送方重傳出現錯誤的資料,同時在接收方來不及處理收到的資料時,及時告訴傳送方適當降低傳送資料的速度。這樣一來,本來是不可靠的傳輸通道就能夠實現可靠傳輸了。

TCP的可靠性表現在:它嚮應用層提供的資料是無差錯的、有序的、無丟失的。簡單的說就是,TCP最終遞交給應用層的資料和傳送者傳送的資料是一模一樣的。

TCP採用了流量控制、擁塞控制、連續ARQ等技術來保證它的可靠性。

網路層傳輸的資料單元為資料報,傳輸層的資料單元為報文段,但為了方便起見,可以統稱為分組。

5.1 停止等待協議(ARQ協議)

TCP保證其可靠性採用的是更為複雜的滑動視窗協議,但停止等待協議是它的簡化版,為了方便理解,這裡先介紹停止等待協議。

(1) AQR協議

ARQ(Automatic Repeat reQuest)自動重傳請求。

顧名思義,當請求失敗時它會自動重傳,直到請求被正確接收為止。這種機制保證了每個分組都能被正確接收。停止等待協議是一種ARQ協議。

(2) 停止等待協議的原理

(a) 無差錯的情況

A向B每傳送一個分組,都要停止傳送,等待B的確認應答;A只有收到了B的確認應答後才能傳送下一個分組。

(b) 分組丟失和出現差錯的情況

傳送者擁有超時計時器。每傳送一個分組便會啟動超時計時器,等待B的應答。若超時仍未收到應答,則A會重發剛才的分組。

分組出現差錯:

若B收到分組,但通過檢查和欄位發現分組在運輸途中出現差錯,它會直接丟棄該分組,並且不會有任何其他動作。A超時後便會重新發送該分組,直到B正確接收為止。

分組丟失:

若分組在途中丟失,B並沒有收到分組,因此也不會有任何響應。當A超時後也會重傳分組,直到正確接收該分組的應答為止。

綜上所述:當分組丟失 或 出現差錯 的情況下,A都會超時重傳分組。

(c) 應答丟失和應答遲到的情況

TCP會給每個位元組都打上序號,用於判斷該分組是否已經接收。

應答丟失:

若B正確收到分組,並已經返回應答,但應答在返回途中丟失了。此時A也收不到應答,從而超時重傳。緊接著B又收到了該分組。接收者根據序號來判斷當前收到的分組是否已經接收,若已接收則直接丟棄,並補上一個確認應答。

應答遲到:

若由於網路擁塞,A遲遲收不到B傳送的應答,因此會超時重傳。B收到該分組後,發現已經接收,便丟棄該分組,並向A補上確認應答。A收到應答後便繼續傳送下一個分組。但經過了很長時間後,那個失效的應答最終抵達了A,此時A可根據序號判斷該分組已經接收,此時只需簡單丟棄即可。

(3) 停止等待協議的注意點

每傳送完一個分組,該分組必須被保留,直到收到確認應答為止。

必須給每個分組進行編號。以便按序接收,並判斷該分組是否已被接收。

必須設定超時計時器。每傳送一個分組就要啟動計時器,超時就要重發分組。

計時器的超時時間要大於應答的平均返回時間,否則會出現很多不必要的重傳,降低傳輸效率。

5.2 滑動視窗協議(連續ARQ協議)

(1) 連續ARQ協議

在ARQ協議傳送者每次只能傳送一個分組,在應答到來前必須等待。而連續ARQ協議的傳送者擁有一個傳送視窗,傳送者可以在沒有得到應答的情況下連續傳送視窗中的分組。這樣降低了等待時間,提高了傳輸效率。

(2) 累計確認

在連續ARQ協議中,接收者也有個接收視窗,接收者並不需要每收到一個分組就返回一個應答,可以連續收到分組之後統一返回一個應答。這樣能節省流量。

TCP頭部的ack欄位就是用來累計確認,它表示已經確認的位元組序號+1,也表示期望傳送者傳送的下一個分組的起始位元組號。

(3) 傳送視窗

傳送視窗的大小由接收視窗的剩餘大小決定。接收者會把當前接收視窗的剩餘大小寫入應答TCP報文段的頭部,傳送者收到應答後根據該值和當前網路擁塞情況設定傳送視窗的大小。傳送視窗的大小是不斷變化的。

傳送視窗由三個指標構成:

(a) p1

p1指向傳送視窗的後沿,它後面的位元組表示已經發送且已收到應答。

(b) p2

p2指向尚未傳送的第一個位元組。

p1-p2間的位元組表示已經發送,但還沒收到確認應答。這部分的位元組仍需保留,因為可能還要超時重發。

p2-p3間的位元組表示可以傳送,但還沒有傳送的位元組。

(c) p3

p3指向傳送視窗的前沿,它前面的位元組尚未傳送,且不允許傳送。

傳送者每收到一個應答,後沿就可以向前移動指定的位元組。此時若視窗大小仍然沒變,前沿也可以向前移動指定位元組。

當p2和前沿重合時,傳送者必須等待確認應答。

(4) 接收視窗

接收者收到的位元組會存入接收視窗,接收者會對已經正確接收的有序位元組進行累計確認,傳送完確認應答後,接收視窗就可以向前移動指定位元組。

如果某些位元組並未按序收到,接收者只會確認最後一個有序的位元組,從而亂序的位元組就會被重新發送。

(5) 連續ARQ的注意點

(a) 同一時刻傳送視窗的大小並不一定和接收視窗一樣大。

雖然傳送視窗的大小是根據接收視窗的大小來設定的,但應答在網路中傳輸是有時間的,有可能t1時間接收視窗大小為m,但當確認應答抵達傳送者時,接收視窗的大小已經發生了變化。此外發送視窗的大小還隨網路擁塞情況影響。當網路出現擁塞時,傳送視窗將被調小。

(b) TCP標準並未規定未按序到達的位元組的處理方式。但TCP一般都會快取這些位元組,等缺少的位元組到達後再交給應用層處理。這比直接丟棄亂序的位元組要節約頻寬。

(c) TCP標準規定接收方必須要有累計確認功能。接收方可以對多個TCP報文段同時確認,但不能拖太長時間,一般是0.5S以內。此外,TCP允許接收者在有資料要傳送的時候捎帶上確認應答。但這種情況一般較少,因為一般很少有兩個方向都要傳送資料的情況。

6 流量控制

6.1 視窗概述

TCP採用大小可變的滑動視窗進行流量控制,視窗大小的單位是位元組。傳送視窗在連線建立時由雙方商定。但在通訊的過程中,接收端可根據自己的資源情況,隨時動態地調整對方的傳送視窗上限值(可增大或減小)。

(1) 為什麼要設定視窗?

我們可以把視窗理解為緩衝區(但是有些視窗和緩衝區又不太一樣)。如果沒有這些“視窗”,那麼TCP沒傳送一段資料後都必須等到接收端確認後才能傳送下一段資料(否則會出現接收端資料來不及處理,資料丟失的情況),這樣做的話TCP傳輸的效率實在是太低了。

解決的辦法就是在傳送端等待確認的時候繼續傳送資料,假設傳送到第X個數據段是收到接收端的確認資訊,如果X在可接受的範圍內那麼這樣做也是可接受的。這就是視窗(緩衝區)引入的緣由。

(2) 視窗分類

(a) 接收端視窗 rwnd     

接收端緩衝區大小。接收端將此視窗值放在 TCP 報文的首部中的視窗欄位,傳送給傳送端。

(b) 擁塞視窗 cwnd (congestion window)    

傳送端緩衝區大小

(c) 傳送視窗swnd

 傳送視窗的上限值 = Min [rwnd, cwnd]

當 rwnd < cwnd 時,是接收端的接收能力限制傳送視窗的最大值。

當 cwnd < rwnd 時,則是網路的擁塞限制傳送視窗的最大值。 

6.2 利用滑動視窗實現流量控制

一般來說,我們總是希望資料傳輸的更快一些,但如果傳送方把資料傳送的很快,而接收方來不及接收,這就可能造成資料的丟失。流量控制就是讓傳送方的傳送速率不要太快,讓接收方來得及接收。流量控制是利用滑動視窗機制實現的。

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

從圖中可以看出,B進行了三次流量控制。第一次把視窗減少到 rwnd = 300 ,第二次又減到了 rwnd = 100 ,最後減到 rwnd = 0 ,即不允許傳送方再發送資料了。這種使傳送方暫停傳送的狀態將持續到主機B重新發出一個新的視窗值為止。

我們考慮一種特殊情況,如果B在向A傳送了零視窗報文段後不久,B的接收快取又有了一些儲存空間,於是B向A傳送了一個rwnd=400的報文段,然而這個報文段在傳送過程中丟失了,A就一直等待B傳送非零視窗的報文通知,而B一直等待A傳送資料,如果沒有任何措施的話,這話死鎖的局面會一直延續下去。

為了解決這個問題,TCP為每一個連線設有一個持續計時器(也叫堅持定時器)。只要TCP連線的一方收到對方的零視窗通知,就啟動持續計時器。若持續計時器設定的時間到期,就傳送一個零視窗控測報文段(攜1位元組的資料),對方在收到探測報文段後,在對該報文段的確認時給出現在的視窗值,如果視窗值仍然是零,則收到這個報文段的一方就重新設定持續計時器,如果視窗不為零,那麼死鎖的僵局就被打破了。

6.3 必須考慮傳輸速率

糊塗視窗綜合證: TCP接收方的快取已滿,而互動式的應用程序一次只從接收快取中讀取1位元組(這樣就使接收快取空間僅騰出1位元組),然後向傳送方傳送確認,並把視窗設定為1個位元組(但傳送的資料報為40位元組的的話)。接收,傳送方又發來1個位元組的資料(傳送方的IP資料報是41位元組)。接收方發回確認,仍然將視窗設定為1個位元組。這樣,網路的效率很低。要解決這個問題,可讓接收方等待一段時間,使得或者接收快取已有足夠空間容納一個最長的報文段,或者等到接收方快取已有一半空閒的空間。只要出現這兩種情況,接收方就發回確認報文,並向傳送方通知當前的視窗大小。此外,傳送方也不要傳送太小的報文段,而是把資料報積累成足夠大的報文段,或達到接收方快取的空間的一半大小。

7 擁塞控制

7.1 概述

(1) 擁塞

即對資源的需求超過了可用的資源。若網路中許多資源同時供應不足,網路的效能就要明顯變壞,整個網路的吞吐量隨之負荷的增大而下降。

(2) 擁塞控制(擁塞視窗--->傳送視窗)

防止過多的資料注入到網路中,這樣可以使網路中的路由器或鏈路不致過載。擁塞控制所要做的都有一個前提:網路能夠承受現有的網路負荷。擁塞控制是一個全域性性的過程,涉及到所有的主機、路由器,以及與降低網路傳輸效能有關的所有因素。

(3) 流量控制(接收視窗--->傳送視窗)

指點對點通訊量的控制,是端到端的問題。流量控制所要做的就是抑制傳送端傳送資料的速率,以便使接收端來得及接收。

(4) 擁塞控制代價

需要獲得網路內部流量分佈的資訊。在實施擁塞控制之前,還需要在結點之間交換資訊和各種命令,以便選擇控制的策略和實施控制。這樣就產生了額外的開銷。擁塞控制還需要將一些資源分配給各個使用者單獨使用,使得網路資源不能更好地實現共享。

(5) 幾種擁塞控制方法

慢開始( slow-start )、擁塞避免( congestion avoidance )、快重傳( fast retransmit )和快恢復( fast recovery )。

7.2 慢開始與擁塞避免

傳送方維持一個叫做擁塞視窗cwnd(congestion window)的狀態變數。擁塞視窗的大小取決於網路的擁塞程度,並且動態地在變化。傳送方讓自己的傳送視窗等於擁塞視窗,另外考慮到接受方的接收能力,傳送視窗可能小於擁塞視窗。

慢開始(slow start threshold)演算法的思路就是,不要一開始就傳送大量的資料,先探測一下網路的擁塞程度,也就是說由小到大逐漸增加擁塞視窗的大小。

這裡用報文段的個數的擁塞視窗大小舉例說明慢開始演算法,實時擁塞視窗大小是以位元組為單位的。如下圖:

當然收到單個確認但此確認多個數據報的時候就加相應的數值。所以一次傳輸輪次之後擁塞視窗就加倍。這就是乘法增長,和後面的擁塞避免演算法的加法增長比較。

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

當cwnd<ssthresh時,使用慢開始演算法。

當cwnd>ssthresh時,改用擁塞避免演算法。

當cwnd=ssthresh時,慢開始與擁塞避免演算法任意。

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

無論是在慢開始階段還是在擁塞避免階段,只要傳送方判斷網路出現擁塞(其根據就是沒有收到確認,雖然沒有收到確認可能是其他原因的分組丟失,但是因為無法判定,所以都當做擁塞來處理),就把慢開始門限設定為出現擁塞時的傳送視窗大小的一半。然後把擁塞視窗設定為1,執行慢開始演算法。如下圖:

再次提醒這裡只是為了討論方便而將擁塞視窗大小的單位改為資料報的個數,實際上應當是位元組。

(1) 當TCP連線進行初始化時,把擁塞視窗cwnd置為1。前面已說過,為了便於理解,圖中的視窗單位不使用位元組而使用報文段的個數。慢開始門限的初始值設定為16個報文段,即 cwnd = 16 。

(2) 在執行慢開始演算法時,擁塞視窗 cwnd 的初始值為1。以後傳送方每收到一個對新報文段的確認ACK,就把擁塞視窗值另1,然後開始下一輪的傳輸(圖中橫座標為傳輸輪次)。因此擁塞視窗cwnd 隨著傳輸輪次按指數規律增長。當擁塞視窗cwnd增長到慢開始門限值ssthresh時(即當cwnd=16時),就改為執行擁塞控制演算法,擁塞視窗按線 性規律增長。

(3) 假定擁塞視窗的數值增長到24時,網路出現超時(這很可能就是網路發生擁塞了)。更新後的ssthresh值變為12(即變為出現超時時的擁塞視窗數值 24的一半),擁塞視窗再重新設定為1,並執行慢開始演算法。當cwnd=ssthresh=12時改為執行擁塞避免演算法,擁塞視窗按線性規律增長,每經過 一個往返時間增加一個MSS的大小。

強調:“擁塞避免”並非指完全能夠避免了擁塞。利用以上的措施要完全避免網路擁塞還是不可能的。“擁塞避免”是說在擁塞避免階段將擁塞視窗控制為按線性規律增長,使網路比較不容易出現擁塞。

7.3 快重傳和快恢復

快重傳要求接收方在收到一個失序的報文段後就立即發出重複確認(為的是使傳送方及早知道有報文段沒有到達對方)而不要等到自己傳送資料時捎帶確認。快重傳演算法規定,傳送方只要一連收到三個重複確認就應當立即重傳對方尚未收到的報文段,而不必繼續等待設定的重傳計時器時間到期。如下圖:

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

(1) 當傳送方連續收到三個重複確認時,就執行“乘法減小”演算法,把ssthresh門限減半。但是接下去並不執行慢開始演算法。

(2) 考慮到如果網路出現擁塞的話就不會收到好幾個重複的確認,所以傳送方現在認為網路可能沒有出現擁塞。所以此時不執行慢開始演算法,而是將cwnd設定為ssthresh的大小,然後執行擁塞避免演算法。如下圖:

在採用快恢復演算法時,慢開始演算法只是在TCP連線建立時和網路出現超時時才使用。

採用這樣的擁塞控制方法使得TCP的效能有明顯的改進。

接收方根據自己的接收能力設定了接收視窗rwnd,並把這個視窗值寫入TCP首部中的視窗欄位,傳送給傳送方。因此,接收視窗又稱為通知視窗。因此,從接收方對傳送方的流量控制的角度考慮,傳送方的傳送視窗一定不能超過對方給出的接收視窗rwnd 。

傳送方視窗的上限值 = Min [ rwnd, cwnd ]

當rwnd < cwnd 時,是接收方的接收能力限制傳送方視窗的最大值。

當cwnd < rwnd 時,則是網路的擁塞限制傳送方視窗的最大值。

7.4 隨機早期檢測RED

以上的擁塞避免演算法並沒有和網路層聯絡起來,實際上網路層的策略對擁塞避免演算法影響最大的就是路由器的丟棄策略。在簡單的情況下路由器通常按照先進先出的策略處理到來的分組。當路由器的快取裝不下分組的時候就丟棄到來的分組,這叫做尾部丟棄策略。這樣就會導致分組丟失,傳送方認為網路產生擁塞。更為嚴重的是網路中存在很多的TCP連線,這些連線中的報文段通常是複用路由路徑。若發生路由器的尾部丟棄,可能影響到很多條TCP連線,結果就是這許多的TCP連線在同一時間進入慢開始狀態。這在術語中稱為全域性同步。全域性同步會使得網路的通訊量突然下降很多,而在網路恢復正常之後,其通訊量又突然增大很多。

為避免發生網路中的全域性同步現象,路由器採用隨機早期檢測(RED:randomearly detection)。該演算法要點如下:

使路由器的佇列維持兩個引數,即佇列長隊最小門限min和最大門限max,每當一個分組到達的時候,RED就計算平均佇列長度。然後分情況對待到來的分組:

(1) 平均佇列長度小於最小門限——把新到達的分組放入佇列排隊。

(2) 平均佇列長度在最小門限與最大門限之間——則按照某一概率將分組丟棄。

(3) 平均佇列長度大於最大門限——丟棄新到達的分組。

RED不是等到已經發生擁塞後才把所有佇列尾部的分組全部丟棄,而是在檢測到網路擁塞的早期徵兆時(即路由器的平均佇列長度超過一定門限值時),以概率p隨機丟棄分組,讓擁塞控制只在個別的TCP連線上執行,因而避免全域性性的擁塞控制。

RED的關鍵就是選擇三個引數最小門限、最大門限、丟棄概率和計算平均佇列長度。最小門線必須足夠大,以保證路由器的輸出鏈路有較高的利用率。而最大門限和最小門限只差也應該足夠大,是的在一個TCP往返時間RTT中佇列的正常增長仍在最大門限之內。經驗證明:使最大門限等於最小門限的二倍是合適的。

平均佇列長度採用加權平均的方法計算平均佇列長度,這和往返時間(RTT)的計算策略是一樣的。