【計算機網絡系列(四)】TCP 與 UDP 詳解

UDP協議

  UDP協議存在的必要性,網絡層的IP協議中並沒有端口(port)的概念,IP協議進行的是IP地址到IP地址的傳輸,計算機和計算機之間的對話。但每臺計算機中需要有多個通信通道,並將多個通信通道分配給不同的進程使用。一個端口就代表了這樣的一個通信通道。UDP正是爲了端到端的通信而存在的。
  UDP協議看作IP協議暴露在傳輸層的一個接口,儘管UDP協議非常簡單,但它的產生晚於更加複雜的TCP協議。對於一些簡單的通信,有時候只需要UDP這樣簡單的協議就足夠了。

UDP協議的特點 

UDP協議在IP協議上增加了複用、分用和差錯檢測功能。UDP的特點:
  a. 是無連接的。相比於TCP協議,UDP協議在傳送數據前不需要建立連接,當然也就沒有釋放連接。
  b.是盡最大努力交付的。也就是說UDP協議無法保證數據能夠準確的交付到目的主機。也不需要對接收到的UDP報文進行確認。
  c.是面向報文的。也就是說UDP協議將應用層傳輸下來的數據封裝在一個UDP包中,不進行拆分或合併。因此,運輸層在收到對方的UDP包後,會去掉首部後,將數據原封不動的交給應用進程。
  d.沒有擁塞控制。因此UDP協議的發送速率不受網絡的擁塞度影響。
  e.UDP支持一對一、一對多、多對一和多對多的交互通信。
  f.UDP的頭部佔用較小,只佔用8個字節。
  

UDP協議的格式 

  UDP協議分爲首部字段和數據字段,其中首部字段只佔用8個字節,分別是個佔用兩個字節的源端口、目的端口、長度和檢驗和。

  這裏寫圖片描述

  長度:UDP報文的整個大小,最小爲8個字節(僅爲首部)。
  檢驗和:在進行檢驗和計算時,會添加一個僞首部一起進行運算。僞首部(佔用12個字節)爲:4個字節的源IP地址、4個字節的目的IP地址、1個字節的0、一個字節的數字17、以及佔用2個字節UDP長度。
  UDP計算校驗和的方法和計算IP數據報首部校驗和的方法相似。 但不同的是:IP數據報的校驗和只檢驗IP數據報的首部,但UDP的校驗和是將首部和數據部分一起都檢驗。 在發送端,首先是將全零放入檢驗和字段。再將僞首部以及UDP用戶數據報看成是由許多16bit的字串接起來。 若UDP用戶數據報的數據部分不是偶數個字節,則要填入一個全零字節(即:最後一個基數字節應是16位數的高字節而低字節填0)。 然後按二進制反碼計算出這些16bit字的和(兩個數進行二進制反碼求和的運算的規則是:從低位到高位逐列進行計算。 0和0相加是0,0和1相加是1,1和1相加是0但要產生一個進位1,加到下一列。若最高位相加後產生進位,則最後得到的結果要加1)。 將此和的二進制反碼寫入校驗和字段後,發送此UDP用戶數據報。 在接收端,將收到的UDP用戶數據報連同僞首部(以及可能的填充全零字節)一起,按二進制反碼求這些16bit字的和。 當無差錯時其結果應全爲1。否則就表明有差錯出現, 接收端就應將此UDP用戶數據報丟棄(也可以上交給應用層,但附上出現了差錯的警告)。

這裏寫圖片描述

TCP協議

  TCP(Transportation Control Protocol)協議與IP協議是一同產生的。事實上,兩者最初是一個協議,後來才被分拆成網絡層的IP和傳輸層的TCP。我們已經在UDP協議中介紹過,UDP協議是IP協議在傳輸層的“傀儡”,用來實現數據包形式的通信。而TCP協議則實現了“流”形式的通信。
  

"流"通信

  計算機數據的本質是有序的0/1序列 (如果以byte爲單位,就叫做文本流)。計算機的功能就是儲存和處理文本流。IP協議(參考協議森林03, 05)和UDP協議採用的是數據包的方式傳送,後發出的數據包可能早到,我們並不能保證數據到達的次序。TCP協議確保了數據到達的順序與文本流順序相符。當計算機從TCP協議的接口讀取數據時,這些數據已經是排列好順序的“流”了。比如我們有一個大文件要從本地主機發送到遠程主機,如果是按照“流”接收到的話,我們可以一邊接收,一邊將文本流存入文件系統。這樣,等到“流”接收完了,硬盤寫入操作也已經完成。如果採取UDP的傳輸方式,我們需要等到所有的數據到達後,進行排序,才能組裝成大的文件。這種情況下,我們不得不使用大量的計算機資源來存儲已經到達的數據,直到所有數據都達到了,才能開始處理。
  如果一個文本流很長的話,我們不可能將整個文本流放入到一個IP數據包中,那樣有可能會超過MTU。所以,TCP協議封裝到IP包的不是整個文本流,而是TCP協議所規定的片段(segment)。與之前的一個IP或者UDP數據包類似,一個TCP片段同樣分爲頭部(header)和數據(payload)兩部分, TCP片段的頭部(header)會存有該片段的序號(sequence number)。這樣,接收的計算機就可以知道接收到的片段在原文本流中的順序了,也可以知道自己下一步需要接收哪個片段以形成流。比如已經接收到了片段1,片段2,片段3,那麼接收主機就開始期待片段4。如果接收到不符合順序的數據包(比如片段8),接收方的TCP模塊可以拒絕接收,從而保證呈現給接收主機的信息是符合次序的“流”。

可靠性

  片段編號這個初步的想法並不能解決我們所有的問題。IP協議是不可靠的,所以IP數據包可能在傳輸過程中發生錯誤或者丟失。而IP傳輸是”Best Effort” 式的,如果發生異常情況,我們的IP數據包就會被輕易的丟棄掉。另一方面,如果亂序(out-of-order)片段到達,根據我們上面說的,接收主機不會接收。這樣,錯誤片段、丟失片段和被拒片段的聯手破壞之下,接收主機只可能收到一個充滿“漏洞”的文本流。
  TCP的補救方法是,在每收到一個正確的、符合次序的片段之後,就向發送方(也就是連接的另一段)發送一個特殊的TCP片段,用來知會(ACK,acknowledge)發送方:我已經收到那個片段了。這個特殊的TCP片段叫做ACK回覆。如果一個片段序號爲L,對應ACK回覆有回覆號L+1,也就是接收方期待接收的下一個發送片段的序號。如果發送方在一定時間等待之後,還是沒有收到ACK回覆,那麼它推斷之前發送的片段一定發生了異常。發送方會重複發送(retransmit)那個出現異常的片段,等待ACK回覆,如果還沒有收到,那麼再重複發送原片段… 直到收到該片段對應的ACK回覆(回覆號爲L+1的ACK)。
   這裏寫圖片描述

滑窗

  上面的工作方式中,發送方保持發送->等待ACK->發送->等待ACK…的單線工作方式,這樣的工作方式叫做stop-and-wait。stop-and-wait雖然實現了TCP通信的可靠性,但同時犧牲了網絡通信的效率。在等待ACK的時間段內,我們的網絡都處於閒置(idle)狀態。我們希望有一種方式,可以同時發送出多個片段。然而如果同時發出多個片段,那麼由於IP包傳送是無次序的,有可能會生成亂序片段(out-of-order)。
  滑窗(sliding window)被同時應用於接收方和發送方,以解決以上問題。就是一個緩存技術。
  以大小爲3的窗口爲例:
  
這裏寫圖片描述
  

TCP協議格式

這裏寫圖片描述
先關注下面幾點:

  1. 一個TCP頭部需要包含出發端口(source port)和目的地端口(destination port)。這些與IP頭中的兩個IP地址共同確定了連接。

  2. 每個TCP片段都有序號(sequence number)。這些序號最終將數據部分的文本片段整理成爲文本流。

  3. ACK是一位(bit)。只有ACK位設定的時候,回覆號(Acknowledgement number)纔有效。ACK回覆號說明了接收方期待接收的下一個片段,所以ACK回覆號爲最後接收到的片段序號加1。

很多時候,ACK回覆“附着”在發送的數據片段中。TCP協議是雙向的。比如A和B兩個電腦。ACK回覆是接收方回覆給發送方 (比如A發送給B, B回覆A)。但同時,B也可以是發送方,B有可能有數據發送給A,所以B就把ACK回覆附着在它要發送給A的數據片段的頭部。這樣可以減少ACK所佔用的交通流量。一個片段可以只包含ACK回覆。一個純粹的ACK回覆片段不傳送文本流,所以不消耗序列號。如果有下一個正常的數據片段,它的序號將與純粹ACK回覆片段的序號相同。

(ACK回覆還可以“附着”在SYN片段和FIN片段)

  1. ACK後面還有SYN和FIN,它們也各佔據一位(bit)。我將在後面說明這兩位。

擁塞控制 

  擁塞控制就是防止過多的數據注入網絡中,這樣可以使網絡中的路由器或鏈路不致過載。擁塞控制是一個全局性的過程,和流量控制不同,流量控制指點對點通信量的控制。

慢啓動與擁塞避免

  發送方維持一個叫做擁塞窗口cwnd(congestion window)的狀態變量。擁塞窗口的大小取決於網絡的擁塞程度,並且動態地在變化。發送方讓自己的發送窗口等於擁塞窗口,另外考慮到接受方的接收能力,發送窗口可能小於擁塞窗口。
慢啓動算法的思路就是,不要一開始就發送大量的數據,先探測一下網絡的擁塞程度,也就是說由小到大逐漸增加擁塞窗口的大小。
實時擁塞窗口大小是以字節爲單位的。
示例以數據包個數方便說明,示例如下圖:
這裏寫圖片描述
  當收到確認後擁塞窗口就加倍,和後面的擁塞避免算法的加法增長比較,其實慢啓動並不慢。
  爲了防止cwnd增長過大引起網絡擁塞,還需設置一個慢開始門限ssthresh狀態變量。ssthresh的用法如下:

  當cwnd < ssthresh時,使用慢啓動算法。

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

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

  擁塞避免算法讓擁塞窗口緩慢增長,即每經過一個往返時間RTT就把發送方的擁塞窗口cwnd加1,而不是加倍。這樣擁塞窗口按線性規律緩慢增長。
  無論是在慢啓動階段還是在擁塞避免階段,只要發送方判斷網絡出現擁塞(其根據就是沒有收到確認,雖然沒有收到確認可能是其他原因的分組丟失,但是因爲無法判定,所以都當做擁塞來處理),就把慢開始門限設置爲出現擁塞時的發送窗口大小的一半。然後把擁塞窗口設置爲1,執行慢開始算法。如下圖:
  這裏寫圖片描述
說明:這裏只是爲了討論方便而將擁塞窗口大小的單位改爲數據報的個數,實際上應當是字節。

快速重傳和快速恢復

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

  快速重傳配合使用的還有快速恢復算法,有以下兩個要點:
  ①當發送方連續收到三個重複確認時,就執行“乘法減小”算法,把ssthresh門限減半。
  ②考慮到如果網絡出現擁塞的話就不會收到好幾個重複的確認,所以發送方現在認爲網絡可能沒有出現擁塞。所以此時不執行慢啓動算法,而是將cwnd設置爲ssthresh的大小,然後執行擁塞避免算法。如下圖:
  這裏寫圖片描述

隨機早期檢測RED

  以上的擁塞避免算法並沒有和網絡層聯繫起來,實際上網絡層的策略對擁塞避免算法影響最大的就是路由器的丟棄策略。在簡單的情況下路由器通常按照先進先出的策略處理到來的分組。當路由器的緩存裝不下分組的時候就丟棄到來的分組,這叫做尾部丟棄策略。這樣就會導致分組丟失,發送方認爲網絡產生擁塞。更爲嚴重的是網絡中存在很多的TCP連接,這些連接中的報文段通常是複用路由路徑。若發生路由器的尾部丟棄,可能影響到很多條TCP連接,結果就是這許多的TCP連接在同一時間進入慢開始狀態。這在術語中稱爲全局同步。全局同步會使得網絡的通信量突然下降很多,而在網絡恢復正常之後,其通信量又突然增大很多。爲避免發生網路中的全局同步現象,路由器採用隨機早期檢測(RED:randomearly detection)。
  使路由器的隊列維持兩個參數,即隊列長隊最小門限min和最大門限max,每當一個分組到達的時候,RED就計算平均隊列長度。然後分情況對待到來的分組:
①平均隊列長度小於最小門限——把新到達的分組放入隊列排隊。
②平均隊列長度在最小門限與最大門限之間——則按照某一概率將分組丟棄。
③平均隊列長度大於最大門限——丟棄新到達的分組。

這裏寫圖片描述
  以概率p隨機丟棄分組,讓擁塞控制只在個別的TCP連接上執行,因而避免全局性的擁塞控制。
  RED的關鍵就是選擇三個參數最小門限、最大門限、丟棄概率和計算平均隊列長度。平均隊列長度採用加權平均的方法計算平均隊列長度,這和往返時間(RTT)的計算策略是一樣的。
  這裏寫圖片描述
  這裏寫圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章