1. 程式人生 > >傳輸控制協議(transmission control protocol)——TCP 整理

傳輸控制協議(transmission control protocol)——TCP 整理

概述

TCP 使用 GBN 和 SR 協議的組合來提供可靠性。為了實現這個目的,TCP 使用校驗和(為差錯發現)、丟失或被破壞分組重傳、
累積和選擇確認以及計時器。

 

 

TCP服務

1、TCP使用埠號來實現程序間通訊

2、TCP 是一個面向流的協議。TCP 允許傳送程序以位元組流形式傳遞資料,並且接收程序也以位元組流形式接收數
據。

3、因為傳送和接收程序可能以不同的速度寫入和讀出資料,所以 TCP 需要用於儲存的緩衝區。每一個方向都存在一個緩衝區:傳送緩衝區和接收緩衝區。實現緩衝區的一種方法是使用以一位元組為儲存單元的迴圈陣列

      在傳送端,緩衝區有三種類型的儲存單元。白色的部分是空儲存單元,可以由傳送程序(生產者)填充。灰色的部分用於儲存已經發送但還沒有得到確認的位元組。TCP 在緩衝區中保留這些位元組,直到收到確認為止。灰色緩衝區是將要由 TCP 傳送
的位元組。灰色儲存單元的位元組被確認後,這些儲存單元可以回收並且對傳送程序可用。

     接收端的緩衝區操作比較簡單。環形緩衝區分成兩個區域(表示為白色和灰色)。白色區域包含空儲存單元,可以由從網路上接收的位元組進行填充。灰色區域表示接收到的位元組,可以由接收程序讀出。當某個位元組被接收程序讀出以後,這個儲存單元可被回收,並加入到空儲存單元池中。

4、段——IP 層作為 TCP 服務的提供者,需要以分組的方式而不是位元組流的方式傳送資料。、

     在傳輸層,TCP 將多個位元組組合在一起成為一個分組,這個分組稱為段(segment)。TCP 給每個段新增頭部(為了達到控制目的),並將該段傳遞給 IP 層。段被封裝到 IP 資料報中,然後再進行傳輸。整個操作對接收程序是透明的。稍後,我們會看到這些段可能被無序接收、丟失,或者損壞和重發。所有這些均由 TCP 處理,接收程序不會察覺到任何操作。

注意,段的大小不必相同。

5、全雙工通訊——TCP 提供全雙工服務(full-dupler service),即資料可以在同一時間雙向流動。每一方向 TCP都有傳送和接收緩衝區,它們能在雙向傳送和接收段。

6、多路複用和多路分解——與 UDP 不同,TCP 在傳送端執行多路複用,在接收端執行多路分解。然而,由於 TCP 是一個面向連線協議,因此需要為每對程序建立連線。

(我記得一個程序可以開多個socket,這個就為多路複用和多路分解提供了可能。因為:多路複用就是從源主機的不同套接字中收集資料塊,併為每個資料塊封裝上首部資訊從而生成報文段,然後將報文段傳遞到網路層中去。參考連結:

https://blog.csdn.net/ljianhui/article/details/21660629)。

7、面向連線的服務——TCP 段封裝成 IP 資料段,並且可能被無序地傳送,或丟失,或被破壞,然後重發。每個段都可以通過不同的路徑到達目的端。TCP 建立一種面向位元組流的環境,在這種環境中,TCP 能承擔按順序傳遞這些位元組到其他站點的任務。

 

 

 

TCP的特點

1、序號系統——雖然 TCP 軟體能夠記錄傳送或接收的段,但是在段的頭部沒有段序號欄位。TCP 在段的頭部
採用稱為序號(sequence number)確認號(acknowledgment number)的兩個欄位。這兩個欄位指的是位元組序號(,而不是段序號。

2、位元組序號——TCP 為在一個連線中傳輸的所有資料位元組(八位位元組)編號。在每個方向上序號都是獨立的
當 TCP 接收來自程序的一些資料位元組時,TCP 將它們儲存在傳送緩衝區中並給它們編號。不必從0 開始編碼,TCP 在 0 到 之間生成一個隨機數作為第一個位元組的序號,例如,如果隨機數是
1057,並且傳送的全部位元組個數是 6000,那麼這些位元組序號是 1057~7056。

     在每個連線中傳送的位元組都由 TCP 編號,序號開始於一個隨機產生的數。

3、序號——位元組被編號後,TCP 對傳送的每一個段分配一個序號。

在每一個方向上的序號定義如下:
1.第一段的序號是初始序號(initial sequence number,ISN),這是一個隨機數。(ISN在三次握手的時候又會出現)
2.其他段的序號是之前段的序號加之前段攜帶的位元組數(實際上的或想象的)。之後,我們將給出一些控制段,它們被認為攜帶了一個想象位元組。

       一個段的序號欄位的值定義了該段包含的第一個位元組的序號。

4、確認號——確認號定義了該方預期接收的下一個位元組的序號。另外,確認號是累積的,這意味著接收方記下它已安全而且完整地接收到最後一個位元組的序號,然後將它加 1,並將這個結果作為確認號進行通告。

      段中確認欄位的值定義了通訊一方預期接收的下一個位元組的編號。確認號是累積的。

 

 

 

 

在 TCP 中的分組稱為段(segment)。段包含 20 位元組到 60 位元組的頭部,接著是來自應用程式的資料。如果沒有選項,那麼頭部是 20 位元組;如果有選項,最多是 60 位元組。

1、源埠地址。這是一個 16 位的欄位,它定義了在主機中傳送該段的應用程式的埠號。這與 UDP 頭部的源埠地址的作用一樣。
2、目的埠地址。這是一個 16 位的欄位,它定義了在主機中接收該段的應用程式的埠號。這與 UDP 頭部的目的埠地址的作用一樣。
3、 序號。這個 32 位的欄位定義了一個數,它分配給段中資料的第一個位元組。序號告訴目的端,在這個序列中哪一個位元組是該段的第一個位元組。在連線建立時,每一方都使用隨機數生成器產生一個初始序號(initial sequence number,ISN),通常每一個方向的 ISN 都不同。

4、確認號。這個 32 位的欄位定義了段的接收方期望從對方接收的位元組號。如果段的接收方成功地接收了對方發來的位元組號 x,它就將確認號定義為 x + 1,確認和資料可捎帶一起傳送
5、頭部長度。這個 4 位的欄位指明瞭 TCP 頭部中共有多少個 4 位元組長的字。頭部的長度可以在 20 位元組到 60 位元組之間。因此,這個欄位的值在 5(5 × 4 = 20)到 15(15 × 4 = 60)之間。

           

6、視窗大小。這個欄位定義對方必須維持的視窗的大小(以位元組為單位)

注意,這個欄位的長度是 16 位,這意味著視窗的最大長度是 65 535 位元組。這個值通常稱為接收視窗(rwnd),它由接收方確定。此時,傳送方必須服從接收端的支配。
7、 校驗和。這個 16 位的欄位包含了校驗和。TCP 校驗和的計算過程與前面描述的 UDP 所採用的計算過程相同。但是,在 UDP 資料報中校驗和是可選的。然而,對 TCP 來說,將校驗和包含進去是強制的。起相同作用的偽頭部被加到段上。對 TCP 偽頭部,協議欄位的值是6。
8、緊急指示符。這個 16 位的欄位只有當緊急標誌置位時才有效,這個段包含了緊急資料。它定義了一個數,將此數加到序號上就得出此段資料部分中最後一個緊急位元組。

     

 

 

 

 

 

TCP連線

      TCP 是一種面向連線的協議。面向連線的傳輸協議在源端和目的端之間建立一條虛路徑。然後,屬於一個報文的所有段都沿著這條虛路徑傳送。整個報文使用單一的虛路徑有利於確認處理以及對損壞或丟失幀的重發。

      TCP 的連線是虛連線,不是物理連線。TCP 在一個較高層次上操作,TCP 使用 IP服務向接收方傳遞獨立的段,但它控制連線本身。如果一個段丟失了或損壞了,則重新發送它。與TCP 不同,IP 不知道這個重新發送過程。如果一個段失序到達,則 TCP 儲存它直到缺少的段到達。IP 是不知道這個重新排序過程的。

 

1、三次握手(three-way handshaking)

 原因—— TCP 以全雙工方式傳輸資料。當兩個機器中的兩個 TCP 建立連線後,它們就能夠同時向對方傳送段。這就表示,在傳輸資料之前,每一方都必須對通訊進行初始化,並得到對方的認可

a)客戶傳送的第一個段是 SYN 段

這個段僅有 SYN 標誌被置位,它用於序號同步。它佔用一個序號。當資料傳輸開始時,客戶隨機選擇一個數字作為初始序號(ISN)。注意,這個段不包含確認號。它也沒有定義視窗大小;視窗大小的定義只有當段包含確認號時才有意義。SYN 段是一個控制段並且不攜帶資料。然而,它消耗一個序號,因為它需要被確認。我們可以說 SYN 段攜帶了一個假想位元組。
       SYN 段不攜帶資料,但它佔用一個序號

b)伺服器傳送第二個段—— SYN +ACK 段

這個段有兩個目的。首先,它是另一方向通訊的 SYN 段。伺服器使用這個段來初始化序號,這個序號用來給從伺服器發向客戶的位元組編號。伺服器也通過給 ACK 置位並展示下一個序號來確認接收到來自客戶的 SYN 段,這裡的下一個序號是伺服器預期從客戶接收的序號。因為它包含確認,它也需要定義接收視窗,即 rwnd(客戶使用)。因為這個段起到 SYN段的作用,它需要被確認。因此,它佔用一個序號。
        SYN + ACK 段不攜帶資料,但它佔用一個序號。

c)客戶傳送第三個段。這個段僅僅是一個 ACK 段

它使用 ACK 標誌和確認序號欄位來確認收到了第二個段。注意,如果不攜帶資料,ACK 段沒有佔用任何序號。
        ACK 段,如果不攜帶資料,則它不佔用序號。

擴充套件——SYN泛洪攻擊(SYN flooding attack)

在 TCP 中,連線建立過程易遭受到稱為 SYN 泛洪攻擊(SYN flooding attack)的嚴重安全問題。一個惡意的攻擊者將大量的 SYN 段傳送到一個伺服器,在資料報中通過偽裝源 IP 地址假裝這些 SYN 段是來自不同的客戶端,此時就是 SYN 泛洪攻擊。假定客戶機發出主動開啟,伺服器分配必要的資源,如生成轉換控制塊(TCB)和設定計時器等。然後伺服器傳送 SYN+ACK 段給這些假客戶,但這些段都丟失了。然而,當伺服器等待第三段握手過程時,許多資源被佔用但沒有被使用。如果在短時間內,SYN 段的數量很大,伺服器最終會耗盡資源而崩潰。這種 SYN 泛洪攻擊屬於一種稱為拒絕服務攻擊(denial of service attack)的安全攻擊型別,其中,一個攻擊者獨佔系統如此多的服務請求使得系統崩潰,拒絕對每個請求提供服務

 

2、資料傳輸

傳送方的 TCP 使用緩衝區儲存來自發送方應用程式的資料流。傳送方的 TCP 可以選擇段的大小。接收方的 TCP 在資料到達時也將資料進行快取,並當應用程式準備就緒時或當接收端 TCP 認為方便時將這些資料傳遞給應用程式。

在有些情況下,應用程式並不需要這種靈活性。例如,應用程式與另一方應用程式進行互動式通訊。一方的應用程式打算將其擊鍵發給對方應用程式,並希望接收到立即響應。資料的延遲傳輸和延遲傳遞對這個應用程式來說是不可接受的。
TCP 可以處理這種情況。在傳送端的應用程式可請求推送操作。這就表示傳送端的 TCP 不必等待視窗被填滿。它建立一個段就立即將其傳送。傳送端的 TCP 還必須設定推送位(PSH)以告訴接收端的 TCP,這個段所包含的資料必須儘快地傳遞給接收應用程式,而不要等待更多資料的到來。這意味著將面向位元組的 TCP 改為面向塊的 TCP,但是 TCP 可以選擇使用或不使用這個特性。

TCP 是面向位元組流的協議。從應用程式到 TCP 的資料被表示成一串位元組流。資料的每一個位元組在流中佔有一個位置。但是,在某些情況下,應用程式需要傳送緊急(urgent)位元組,某些位元組需要另一端的應用以特殊方式對待。解決方法是傳送一個 URG 標誌置位的段。TCP 的緊急模式是一種服務,傳送端的應用程式通過這種服務將位元組流的某些部分標記為需要接收端特別對待的位元組流。接收端 TCP 將位元組(緊急或非緊急)按序傳遞到應用程式,但是通知應用程式緊急資料的開始和結束。留給應用程式決定如何處理緊急資料。

 

3、連線終止

     交換資料雙方的任一方(客戶或伺服器)都可關閉連線,儘管通常情況下是由客戶端發起。當前大多數對連線終止的實現有兩個方法——三次握手和帶有半關閉選項的四次握手。

三次握手

當前對連線終止的絕大多數實現是三次握手(three-way handshaking)。
a)在正常情況下,在客戶程序接收到一個關閉命令後,客戶的 TCP 傳送第一個段:FIN 段,即其中的 FIN 標誌置位。注意,FIN 段可包含客戶機要傳送的最後資料塊或只是控制段。如果它只是控制段,它僅佔有一個序號因為它需要被確認。如果 FIN 段不攜帶資料,則該段佔用一個序號。
b)伺服器 TCP 接收到 FIN 段後,通知它的程序,併發送第二個段:FIN + ACK 段,證實它接收到來自客戶端的 FIN 段,同時通告另一端連線關閉。這個段還可以包含來自伺服器的最後資料塊。如果它不攜帶資料,則這個段僅佔用一個序號。如果 FIN + ACK 段沒有攜帶資料,則該段僅佔用一個序號。
c)客戶端的 TCP 傳送最後一段,即 ACK 段,來證實它接收到來自伺服器的 FIN 段。這個段包含確認號,它是來自伺服器的 FIN 段的序號加 1。這個段不攜帶資料也不佔用序號

四次握手

      在 TCP 中,一端可以停止傳送資料後,還可以接續接收資料。這就是所謂的半關閉(half-close)。雖然任一端都可發出半關閉,但通常都是由客戶端發起的。當伺服器在開始處理之前需要接收到所有資料,這時就會出現半關閉。

     例如,排序是一個很好的例子。客戶端傳送資料給伺服器進行排序,在開始排序之前,伺服器需要接收到全部資料。這就是說,客戶端傳送全部資料之後,它在客戶到伺服器方向可關閉連線。但為了返回儲存資料,伺服器到客戶方向必須保持開啟。伺服器在接收到資料後還需要時間進行排序;它的向外方向必須保持開啟。

     a)從客戶到伺服器的資料傳輸停止。客戶端通過傳送 FIN 段實現半關閉連線。

     b)伺服器通過傳送ACK 段確認半關閉。然而,伺服器還可以傳送資料。

     c)當伺服器已經發送完被處理的資料時,它傳送一個 FIN 段。

     d)該 FIN 段由客戶端的 ACK 來確認。

    連線半關閉後,資料可以從伺服器傳送給客戶端,而確認可以從客戶端傳送給伺服器。客戶不能再向伺服器傳送任何資料。

連線重置

      在一端的 TCP 可能拒絕連線請求,可能終止已存在的連線,也可能結束空閒連線。所有這些都通過 RST(重置)標誌完成。

 

 

 

 

狀態轉換圖

圖中虛線代表伺服器通常經歷的轉換;黑色實線代表客戶通常經歷的轉換。然而,在某種情況下,伺服器沿著實線進行狀態轉換,客戶沿著虛線進行狀態轉換。藍色線給出特殊情況。

注意,被標記為 ESTABLISHED 的圓角矩形實際上是兩種狀態,一個是客戶狀態,另一個是伺服器狀態,它們用於流量和差錯控制

1、場景示例 —— 一個半關閉場景

      客戶程序向它的 TCP 發出主動開啟命令來請求連線到特定套接字地址。TCP 傳送一個 SYN 段並轉移到SYN-SENT狀態。在收到SYN + ACK段後,TCP傳送了一個ACK段並且進入ESTABLISHED狀態。資料被傳輸,可能是雙向的,並且被確認。當客戶程序沒有資料要傳送了,它發出稱為主動關閉的命令。TCP 傳送 FIN 段並進入 FIN-WAIT-1 狀態。當它接收到 ACK 段,它進入 FIN-WAIT-2 狀態。當客戶接收到 FIN 段時,它傳送一個 ACK 段並進入 TIME-WAIT 狀態。客戶保持這種狀態 2MSL秒。當相應計時器超時,客戶進入 CLOSED 狀態。

      伺服器程序發出被動開啟命令。伺服器 TCP 進入 LISTEN 狀態並且保持這種狀態直到它接收到一個 SYN 段。TCP 之後傳送一個 SYN + ACK 段並且進入 SYN-RCVD 狀態,等待客戶傳送 ACK段。在接收到 ACK 段後,TCP 進入 ESTABLISHED 狀態,這就開始了資料傳輸。TCP 保持這種狀態直到它接收到一個來自客戶的 FIN 段,這表示沒有其他資料要被交換且連線可以被關閉。一旦伺服器接收到 FIN 段,那麼它就向客戶傳送帶有虛擬 EOF 標記的排隊中所有的資料,這意味連線必須被關閉。它傳送一個 ACK 段且進入 CLOSE-WAIT 狀態,但是推遲確認來自客戶的 FIN 段,直到它接收到來自程序的被動關閉命令。在接收到被動關閉命令後,伺服器向客戶傳送 FIN 段並進入 LAST-ACK 狀態,等待最終 ACK。當 ACK 段被從客戶接收,伺服器進入 CLOSE 狀態。

 

 

 

TCP中的視窗

      TCP 在每個方向的資料傳輸上使用兩個視窗(傳送視窗和接收視窗),這意味著雙向通訊有四個視窗。

1、傳送視窗

      傳送視窗大小由接收方(流量控制)和底層網路的擁塞程度(擁塞控制)指定。

TCP 中的傳送視窗與選擇性重複協議中的傳送視窗相似,但是有一些不同:

a)在 SR 中視窗的大小是分組的數量,但是 TCP 中的視窗大小是位元組的數量。儘管 TCP 中實際傳輸是一段接一段發生的,但是控制視窗的變數是以位元組為單位的。

b)在某些實現中,TCP 可以儲存來自程序的資料並且在之後傳送它們,但是我們假設傳送方 TCP 一旦從程序中接收到資料就能夠傳送資料段。

c)選擇性重複協議可能為每個被髮送的分組使用多個計時器,而 TCP 只使用一個計時器

2、接收視窗

TCP 中的接收視窗與 SR 中的接收視窗有兩點不同。

a) TCP 允許接收程序以自己的速率拉資料。這意味著接收方部分被分配緩衝區可以被已接收且確認的位元組佔據,但是它們正在等待被接收程序拉過去。接收視窗大小決定了接收視窗在被淹沒(流量控制)之前可以從傳送方接收的位元組數量。換言之,接收視窗通常稱為 rwnd,可以由下式決定:
             rwnd = 緩衝區大小  − 等待被拉位元組數量

b)在 SR 中的確認是選擇性的,它定義了已經被接收的分組。TCP 中主要確認機制是累積確認,它聲明瞭下一個預期接收位元組。然而,TCP 的新版本使用了累積確認和選擇性確認。

 

 

 

流量控制

流量控制平衡了生產者建立資料的速率與消費者使用資料的速率。TCP 將流量控制與差錯控制分開。

圖 3-56 給出了從傳送方程序到傳送方 TCP、從傳送方 TCP 到接收方 TCP 以及從接收方 TCP上升到接收方程序的資料(路徑 1、2 和 3)傳輸過程。然而,流量控制反饋卻是從接收方 TCP 傳輸到傳送方 TCP 並且從傳送方 TCP 上升到傳送方程序(路徑 4 和 5)。絕大多數 TCP 實現不提供從接收方程序到接收方 TCP 的流量控制反饋;無論何時,當接收方程序準備好了,具體實現就會讓接收方程序從接收方 TCP 中拉資料。

接收方 TCP 控制傳送方 TCP;傳送方 TCP 控制傳送方程序。

 

1、開啟以及關閉視窗

為了實現流量控制,TCP 迫使傳送方和接收方調整它們的視窗大小,儘管當連線建立時兩方的緩衝區大小是固定的

a)當更多的資料從傳送方到來時,接收方視窗關閉(向右移動左沿);

b)當更多的資料被程序拉過來時,它開啟視窗(向右移動右沿)。

傳送視窗的開啟、關閉和收縮由接收方控制

a)當一個新的確認允許傳送視窗關閉時,傳送視窗關閉(向右移動左沿)。

b)當接收方通知的接收視窗大小(rwnd)允許傳送方視窗開啟時(新 ackNo +新 rwnd > 上一個 ackNo + 上一個 rwnd),傳送視窗開啟(向右移動右沿)。這種情況沒有發生的事件中,傳送視窗縮小。

 

2、例子

客戶和伺服器之間交換了 8 個段。

三次握手部分:
a)從客戶到伺服器的第 1 段(SYN 段)請求連線。這個段宣告起始 seqNo = 100。當這個段到達伺服器時,它分配了大小為 800 位元組的緩衝區(假設)並設定視窗覆蓋了全部緩衝區(rwnd =800)。注意,下一個要到達的位元組是 101。
b)第 2 段是從伺服器到客戶的。這是 ACK + SYN 段。段使用 ackNo = 101,這表示它期待接收的位元組從 101 開始。它也聲明瞭客戶可以設定大小為 800 位元組的緩衝區。
c)第 3 段是從客戶到伺服器的 ACK 段。注意,客戶可以定義大小為 2000 的 rwnd,但是,在圖 3-57 中我們不使用這個值,因為通訊是單向的。

資料傳輸部分:
a)在客戶設定了伺服器指定的視窗大小(800)之後,程序推送 200 位元組資料。TCP 客戶給這些位元組編號為從 101 到 300。之後,它建立了一個段併發送到伺服器。段開始位元組數是 101 並且攜帶了 200 位元組。之後客戶視窗調整,表示 200 位元組資料被髮送但是等待確認。當這個段被伺服器接收,這些位元組被儲存,並且接收視窗關閉來表示下一個預期位元組是 301;儲存位元組佔據了緩衝區的 200 位元組。
b)第 5 段是從伺服器到客戶的反饋。伺服器確認了多達 300 個位元組,含第 300 個位元組(預期接收 301 位元組)。這個段也攜帶了減少後的接收視窗大小(600)。在接收這個段之後,客戶從它的視窗中清除確認位元組並關閉它的視窗,這表示下一個待發送位元組是 301。然而,視窗大小減少到 600位元組。儘管分配緩衝區可以儲存 800 位元組,但是視窗不能開啟(向右移動右沿),因為接收方不允許。
c)在程序又推送了 300 個位元組後,第 6 段被客戶傳送。段定義了 seqNo 為 301,幷包含了 300位元組。當這個段到達伺服器,伺服器儲存它們,但是它必須減少自己的視窗大小。在程序拉 100位元組資料後,視窗左邊關閉了 300 位元組,但是右側打開了 100 位元組。結果是視窗大小隻減少了 200位元組。現在接收視窗大小是 400 位元組。
d)在第 7 段,伺服器確認接收資料,並宣告它的視窗大小是 400。當這個段到達客戶,客戶別無選擇,只能再次減少它的視窗,並令視窗大小為伺服器通告的 rwnd = 400。傳送視窗從左側關閉 300 位元組,並從右側開啟 100 位元組。
e)在程序拉另外 200 位元組後,第 8 段也是從來自伺服器的。它的視窗大小增加。現在,新的rwnd 的值是 600。段告知客戶,伺服器仍然期待 601 位元組,但是伺服器視窗大小增加到 600。我們需要提及的是,這個段的傳送依賴於具體實現所規定的策略。一些實現可能不允許在這個時候通告rwnd;伺服器需要在這樣做之前接收一些資料。在這個段到達客戶之後,客戶將視窗開啟 200 位元組而不關閉。結果是視窗增大到 600 位元組。

 

3、視窗收縮

接收視窗不能收縮,但是傳送視窗可以收縮——如果接收方為 rwnd 定義了導致視窗收縮的數值,那麼傳送視窗可以收縮。然而,一些實現不允許收縮傳送視窗。這個限制不允許傳送視窗的右沿向左移動。換言之,接收方需要保持上一個和新的確認之間以及上一個和新 rwnd 值之間的如下關係,以防止傳送視窗收縮。

                新 ackNo +新 rwnd≥上一個 ackNo +上一個 rwnd

不等式是對接收端的命令,它使接收端檢查自己的通告。

 

4、視窗關閉
我們說過,不鼓勵將右沿向左移動來收縮傳送視窗。然而,有一個例外:接收方可以通過傳送rwnd 為 0 來臨時關閉視窗。這隻會在某些原因下發生,即接收方在一段時間內不想接收來自發送方的任何資料。在這種情況下,傳送方並不真的收縮視窗大小,但是它停止傳送資料直到新的通告到達。我們將在後面看到,即使當視窗因為來自接收方的命令而關閉了,傳送方也總可以傳送一個1 位元組資料的資料段。這稱為探測,用來防止死鎖。

 

 

 

差錯控制

TCP 使用差錯控制提供可靠性。差錯控制包括用於檢測並重發損壞段的機制、用於重發丟失的段的機制、用於儲存失序的段直到丟失段到達的機制,以及檢測並丟棄重複段的機制。TCP 中的差錯檢測和糾正通過三種簡單工具來完成:校驗和、確認和超時。

1、校驗和

每個段都包括校驗和欄位,用來檢查損壞的段。如果段被損壞,它將被目的端 TCP 丟棄,並被認為是丟失了。TCP 在每段中強制使用一個 16 位的校驗和。

2、確認

TCP 使用確認方法來證實收到了資料段。不攜帶資料但佔用序號的一些控制段也要確認,但ACK 段是不確認的。
        ACK 段不佔用序號,它不需要確認。

 

確認型別
在過去,TCP 只使用一種型別確認:累積確認。現在,一些 TCP 實現也使用選擇性確認。

累積確認(ACK) 最初的 TCP 被設計成累積確認接收段。接收方通告下一個預期接收的位元組,忽略所有失序段。這有時稱為積極累積確認(positive cumulative acknowledgment)或 ACK。積極這個詞表示不為丟棄、丟失或被破壞的段提供反饋。TCP 頭部的 32 位 ACK 欄位用來累積確認,且只有當 ACK 標誌位置為 1 時才有效

選擇性確認(SACK) 越來越多的實現加入了另外一種稱為選擇性確認(selective acknowledgment)或 SACK 的確認型別。SACK 並不替代 ACK,但它向傳送方報告額外的資訊。SACK 報告失序位元組塊,也報告重複位元組塊即接收了一次以上的位元組塊。然而,因為 TCP 頭部沒有為加入這種型別的資訊做準備,SACK 以一種 TCP 頭部末端選項的形式實現。

 

產生確認

接收方什麼時候產生確認?
1.當終端 A 向終端 B 傳送一個數據段時,它必須包含(捎帶)一個確認,這個確認給出下一個期待接收的序號。這個規則降低了所需段的數量,因此減少了通訊量。
2.當接收方沒有資料要傳送並接收到一個有序段(帶有預期序號),並且之前的段已經被確認,那麼接收方延遲傳送 ACK 段直到另一個段到達,或者過一段時間之後(通常 500ms)。換言之,如果只有一個未完成的有序段,那麼接收方需要延遲傳送 ACK 段。這個規則減少了 ACK 段。
3.當一個帶有接收方預期序號的段到達,且之前一個有序段未被確認,接收方立即傳送一個到這了ACK 段。換言之,任何時候不能多於兩個有序的未確認段存在。這防止了不必要的重傳,它可能引起網路擁塞。
4.當一個失序段到達,且它的序號大於預期,那麼接收方立即傳送一個 ACK 段,宣告下一個預期段的序號。這導致了丟失段的快速重傳(fast retransmission)。
5.當一個丟失段到達,接收方傳送一個 ACK 段,宣告下一個預期序號。這通知接收方被報告丟失的段已經到達。
6.如果重複段到達,接收方丟棄段,但是立即傳送一個確認指出下一個預期的有序段。這個方法解決了當 ACK 段丟失時的一些問題。

 

重傳

差錯控制機制的核心是段的重傳。當一個段被髮送,它就被儲存在一個佇列中直到被確認。當重傳計時器超時或當傳送方接收到對佇列中的第一個段的三次重複 ACK 時,就重傳這個段。

RTO 之後重傳
傳送方 TCP 為每個連線維護一個重傳超時(retransmission time-out,RTO)。當計時器到時,即超時,TCP 重發佇列前面的段(具有最小序號的段)並重啟計時器。注意, RTO 的數值在 TCP 中是動態的,並根據段的往返時間(round-trip time,RTT)進行更新。RTT 是一個段到達目的端並接收到一個確認所需要的時間
 

三次重複 ACK 段之後重傳
快速重傳(fast retransmission):如果三個對同一個段的重複確認(即一個原始 ACK 加上三個完全相同的副本)到達,那麼下一個段就被重傳而不必等待超時。

 

 

 

 

TCP擁塞控制

擁塞視窗
當我們討論 TCP 中的流量控制,我們曾提到過接收方使用 rwnd 的數值來控制傳送視窗,它在每個沿相反方向傳遞的段中被通告。使用這個策略保證了接收視窗不會被接收位元組溢位(沒有終端擁塞)。然而,這不意味著中間緩衝區、路由器中的緩衝區不會變得擁塞。路由器可能從不止一個傳送端接收資料。無論路由器的緩衝多大,它都可能被資料淹沒,這導致特定 TCP 傳送方丟棄某

些段。換言之,在另一端不存在擁塞,但是可能在中間存在擁塞。TCP 需要擔心中間的擁塞,因為很多丟失段可能導致差錯控制。更多的段丟失意味著再次重發相同的段,導致擁塞更嚴重,並且最終導致通訊崩潰。

TCP 是使用 IP 服務的端到端協議。路由器中的擁塞是在 IP 域內,並且應該由 IP 解決。然而,IP 是一個沒有擁塞控制的簡單協議。TCP 自身需要為這個問題負責。

TCP 使用稱為擁塞視窗(congestion window,cwnd)的變數來控制段的傳送數量,這個變數的值由網路中的擁塞情況所控制。cwnd 變數和 rwnd 變數一起定義了 TCP 中的傳送視窗大小。第一個變數與中間的擁塞相關(網路);第二個變數與終端的擁塞相關。實際視窗的大小是這兩者中的最小值。   

                   實際視窗大小 = minimum (rwnd, cwnd)

擁塞檢測
TCP 傳送方使用兩個事件作為網路中擁塞的標誌:超時和接收到三次重複 ACK。
第一個是超時(time-out)。如果一個 TCP 傳送方在超時之前沒有接收到對於某個段或某些段的 ACK,那麼它就假設相應段或相應那些段丟失了,並且丟失是擁塞引起的。
另一個事件是接收到三次重複 ACK(四個帶有相同確認號的 ACK)。回憶當 TCP 接收方傳送一個重複 ACK,這是段已經被延遲的訊號,但是傳送三次重複 ACK 是丟失段的標誌,這可能是由於網路擁塞造成的。然而,在三次重複 ACK 的情況下擁塞的嚴重程度低於超時情況。當接收方傳送三次重複 ACK 時,這意味著一個段丟失,但是三個段已經被接收到。網路或者輕微擁塞或者從已經從擁塞中恢復。
TCP 擁塞中非常有趣的一點是,TCP 傳送方只使用一種反饋從另一端來檢測擁塞:即 ACK。沒有周期性地、及時地接收到 ACK,這導致超時,是嚴重擁塞的標誌;接到三次重複 ACK 是網路中輕微擁塞的標誌

 

擁塞策略
TCP 處理擁塞的一般策略基於三個演算法:慢啟動、擁塞避免和快速恢復

慢啟動:指數增加
慢啟動(slow-start)演算法是基於擁塞視窗大小(cwnd)的思想,它以最大段長度(MSS)開始,但是每當一個確認到達時它只增加一個 MSS。

看圖 3-66。我們假設 rwnd 比 cwnd 大得多,因此傳送視窗大小永遠等於 cwnd。我們也假設每個段是同長度的,並攜帶 MSS 位元組。為了簡單起見,我們也忽略延遲 ACK 策略並假設每個段單獨被確認。

傳送方以 cwnd = 1 開始。這意味著傳送方僅能傳送一個段。當第一個 ACK 到達後,被確認的段被從視窗中清除,這意味著現在視窗中有一個空段槽。擁塞視窗的大小也增加 1,因為收到確認標誌著網路中沒有擁塞。視窗的大小現在是 2。在傳送兩個段並接收到兩個獨立的確認之後,現在擁塞視窗的大小是 4,依此類推。換言之,在這個演算法中擁塞視窗的大小是到達 ACK 數量的函式,可由下式決定。

                       如果一個 ACK 到達,cwnd = cwnd + 1

如果我們按照往返時間(RTT)觀察 cwnd 的大小,那麼我們發現其增長速率是指數的,這是一個非常激進的方法:

慢啟動不能一直繼續下去。肯定存在一個停止該階段的閾值。傳送方儲存一個稱為 ssthresh(slow-start threshold,慢啟動閾值)的變數。當視窗中的位元組達到這個閾值時,慢啟動停止且下一個階段開始。

在慢啟動演算法中,擁塞視窗大小按指數規律增長直到到達閾值。然而,我們已經提到慢啟動策略在延遲確認情況下更慢。請記住,對於每個 ACK,cwnd 值增加 1。因此,如果兩個段被累積確認,cwnd 大小隻增加 1 不是 2。增長仍是指數的,但是它不是 2的冪。對於確認了兩個段的 ACK,它是 1.5 的冪。

擁塞避免:加性增加
如果我們繼續慢啟動演算法,那麼擁塞視窗大小按指數規律增大。為了在擁塞發生之前避免擁塞,必須降低指數增長的速度。TCP 定義了另一個演算法,稱為擁塞避免(congestion avoidance),這個演算法是線性增加 cwnd 而不是指數增加。當擁塞視窗的大小到達慢啟動的閾值時,這種情況下 cwnd= i,慢啟動階段停止且加性增加階段開始。

在這個演算法中,每次整個“視窗”的所有段都被確認(一次傳輸),擁塞窗口才增加 1。視窗是 RTT 期間傳輸的段的數量。圖 3-67 說明了這個概念。傳送方以 cwnd = 4 開始。這意味著傳送方只能傳送 4 個段。在 4 個 ACK 到達之後,被確認的段被從視窗中清除,這意味著現在視窗中有一個空閒段。擁塞視窗也增加 1。視窗大小現在為 5。在傳送 5 個段並接收到 5 個確認之後,擁塞視窗大小變為 6。其餘以此類推。換言之,這個演算法中擁塞視窗的大小也是到達的 ACK 數量的方程,它由下式決定:

                         如果一個 ACK 到達,cwnd = cwnd + (1/cwnd)。

換言之,視窗大小每次只增加 MSS 的 1/cwnd(以位元組為單位)。換言之,視窗中所有段都需要被確認,才能使視窗增加 1MSS 位元組。

如果我們按照往返時間(RTT)觀察 cwnd 的大小,那麼我們會發現其增長速率以每次往返時間為單位是線性的,這比慢啟動方法保守多了。

開始 →  cwnd = i
第一個 RTT 之後  →  cwnd = i + 1
第二個 RTT 之後  →  cwnd = i + 2
第三個 RTT 之後  →  cwnd = i + 3

在擁塞避免演算法中,在檢測到擁塞之前,擁塞視窗大小是加性增加的

快速恢復

快速恢復(fast-recovery)演算法在 TCP 中是可選的。舊版本的 TCP 不使用它,但是新版本使用。快速恢復開始於三次重複 ACK 到達,這被解釋為網路的輕微阻塞。像擁塞避免一樣,這個演算法也是加性增加的,但是當一個重複 ACK 到達時(在三次重複 ACK 觸發使用這個演算法之後),它增加擁塞視窗的大小。我們可以說:
                   如果一個重複 ACK 到達,cwnd = cwnd + (1/cwnd)。

 

 2MSL(2 Maximum Segment Lifetime,2 倍段最大生存時間)