Chapter 12 傳輸控制通訊協定
目標 本章結束後,您將能夠: 可以去列舉並了解 TCP 所提供的服務 了解 TCP 的流量控制、錯誤控制、及壅塞控制 了解預接式連線的各階段 了解 TCP 的狀態轉換圖 熟悉 TCP 的選項
12.1 TCP的服務 我們先看看有哪些應用層的程序使用 TCP 所提供的服務。 本節所討論的主題包括: 程序對程序的通訊 串流傳送服務 全雙工通訊 預接式服務 可靠性服務
範例1 就我們在第11章所說的,在 UNIX 系統中,公認埠號被儲存在 /etc/services 的這個檔案中。檔案中的每一行給予某個服務的名稱及對應的公認埠號。我們可以使用 grep 的系統工具來擷取指定應用所對應的那一行或多行的資料。下面顯示FTP 的埠號:
12.2 TCP的特色 前面章節已經提過 TCP 所提供的服務,而我們會在本節中簡短的概述一下 TCP 的幾項特點。 本節所討論的主題包括: 編號系統 流量控制 錯誤控制 壅塞控制
請注意: 每條連線所傳送的位元組都被 TCP 編號, 第一個號碼是由亂數產生而來。
範例2 想像某一 TCP 連線傳送一個 5,000 位元組的檔案。第一個位元組號碼為 10,001,如果資料被分成 5 個區段送出,每個區段各自攜帶 1,000 個位元組,請問每一個區段的序號為何? 解答 以下是每個區段的序號:
請注意: 區段序號欄的值就是該區段的 第一個位元組資料編號。
請注意: 區段的回應欄之值定義預期接收的 下一個位元組,其回應號碼是累計的。
12.3 區段 在 TCP 中的一個封包稱為一個區段 ( segment ) 。 本節所討論的主題包括: 格式 封裝
請注意: TCP 的檢查碼機制是強制執行的。
12.4 TCP 連線 TCP屬於預接式 ( connection-oriented ) 的傳輸協定,它在來源端與目的端之間建立一條虛擬路徑,所有屬於相同訊息的區段,就依這條虛擬路徑傳送。預接式的傳輸需要以下三個階段:連線的建立、資料的傳輸、及連線的結束。 本節所討論的主題包括: 連線的建立 資料的傳輸 連線的結束
請注意: SYN區段並沒有攜帶任何的資料, 但是它會消耗 1 個序號。
SYN+ACK區段並沒有攜帶任何的資料, 請注意: SYN+ACK區段並沒有攜帶任何的資料, 但是它也會消耗 1 個序號。
請注意: ACK區段並沒有攜帶任何的資料, 它也不會消耗任何的序號。
請注意: 如果FIN區段沒有攜帶任何的資料時, 它只會消耗 1 個序號。
如果FIN+ACK區段沒有攜帶任何的資料時, 請注意: 如果FIN+ACK區段沒有攜帶任何的資料時, 它只會消耗 1 個序號。
12.5 狀態轉換圖 要把連線建立、結束、及資料傳送等各種可能發生的事件追蹤的很好,TCP 軟體是以有限狀態機 ( finite state machine ) 的方式實現。 本節所討論的主題包括: 範例
一般情況下,MSL 的值介於 30 秒到 1 分鐘之間。 請注意: 一般情況下,MSL 的值介於 30 秒到 1 分鐘之間。
12.6 流量控制 流量控制 ( flow control ) 用來管控來源端在收到目的端回應之前能夠送出的資料量。TCP 定義了一個窗口在緩衝器中,這個緩衝器儲存了已經從應用程式傳遞過來,並準備好要被傳送的資料。 本節所討論的主題包括: 滑動窗口協定 傻瓜視窗症候群
接收端不會因為接收太多的資料而無法消化, 請注意: 滑動窗口讓傳輸更有效率, 也用來控制資料的流量, 接收端不會因為接收太多的資料而無法消化, TCP 的滑動窗口是以位元組為計算單位。
範例3 如果接收端 ( B 主機 ) 擁有一個 5,000 位元組大的緩衝器,並且已接收 1,000 個位元組的資料但還沒有處理。請問A 主機之接收端窗口 ( rwnd ) 的值為何? 解答 rwnd = 5,000 – 1,000 = 4,000。 B 主機在它的緩衝器滿出來之前還可以接收 4,000 個位元組。 B 主機會將這個值公布在下一個要傳給 A 的區段中。
範例4 如果 rwnd 的值為 3,000 個位元組,而 cwnd 的值為 3,500 個位元組,請問 A 主機之窗口大小為何? 解答
範例5 圖12.21 說明了一個虛構的滑動窗口之範例。 傳送端已經傳送到第 202 號的位元組資料。我們假設 cwnd 等於 20 ( 實際上這個值可能等於上千個位元組 )。 接收端已經傳送一個 200 號的回應號碼,以及 9 個位元組的 rwnd ( 實際上這個值可能等於上千個位元組 )。 傳送端窗口大小為 rwnd 和 cwnd 中較小的那個值,所以等於 9 個位元組。 第 200 到 202 號的位元組資料已經傳送,但是尚未被回應。第 203 到 208 號的位元組資料可以被傳送,而不需要擔心有關回應與否。第 209 號以上的位元組資料還不能被傳送。
範例 6 在圖12.21中,傳送端接收到一個封包,此封包內含有 202 號的回應號碼及 rwnd=9 等資訊。主機已經將 203、204 和205 號的位元組資料傳送出去。cwnd 的值仍然是 20,請說明新的窗口情況。 解答 圖12.22 說明了新的窗口。注意,在這種情況下,窗口左邊所關閉的位元組個數與右邊所開啟的位元組個數是相同的,窗口的大小並沒有被更動。而 202 號的回應號碼表示第 200和 201 號的位元組資料已經被接收,傳送端不需要再去擔心它們了,窗口可以滑過它們了。
範例7 在圖12.22 中,傳送端接收到一個封包,此封包內含有 206號的回應號碼及 rwnd=12 等資訊。主機並沒有傳送新的位元組資料。cwnd 的值仍然是 20,請說明新的窗口情況。 解答 rwnd 的值小與 cwnd,所以窗口大小為 12。圖12.23 說明了新的窗口情況。注意,窗口的右邊開啟 7 個位元組,窗口的左邊關閉了 4 個位元組;窗口的大小由原本的 9 增加到 12。
範例8 在圖12.23 中,傳送端接收到一個封包,此封包內含有 210 號的回應號碼及 rwnd=5 等資訊。主機已經將 206、207、208 和209 號的位元組資料傳送出去。cwnd 的值仍然是 20 ,請說明新的窗口情況。 解答 rwnd 的值小與 cwnd,所以窗口大小為 5。圖12.24 說明了這樣的情況,注意,這種情況在很多的實作中是不被允許的,儘管傳送端還沒有送出 215 到 217 號的位元組資料,但是接收端並不知道這件事。
範例9 接收端要如何避免先前範例中窗口大小被收縮的情況發生? 解答 接收端需要去記錄最後的回應號碼及最後的 rwnd 值。如果我們將回應號碼與 rwnd 相加的話會得到接在窗口右牆之後的位元組編號。如果我們希望去防止右牆往左移動 ( 收縮 ) 的情況發生,我們必須保持下面的關係:
為了去避免收縮傳送端之窗口,接收端必須等待其緩衝器中有更多的空間被釋放。 請注意: 為了去避免收縮傳送端之窗口,接收端必須等待其緩衝器中有更多的空間被釋放。
請注意: 有關滑動窗口的幾個觀念: 窗口大小等於 rwnd 和 cwnd 中較小的那個值。 來源端不需要將整個窗口大小的資料一次送完。 窗口的大小可由接收端的要求而開啟或關閉,但是不應該被收縮。 接收端可在任何時候送出回應,只要它不會造成窗口收縮的情況。 接收端可以暫時把窗口關閉;然而,在窗口關閉後,傳送端還是可以繼續傳送僅包含 1 位元組資料的區段。
12.7 錯誤控制 TCP 使用錯誤控制 ( error control ) 的機制來提供可靠性。錯誤控制包含了偵測受損的區段、遺失的區段、亂序的區段、及重複的區段之各種機制,錯誤控制當然也包含將偵測到的問題加以修正的機制。TCP使用 3 種簡單的工具來達到錯誤偵測與更正的功能,分別是檢查碼 ( checksum )、回應 ( acknowledgement )、及計時控制 ( time-out )。 本節所討論的主題包括: 檢查碼 回應 回應種類 重送 亂序的區段 相關範例
請注意: ACK區段並沒有消耗任何序號, 所以不需要被回應。
在最新的實作中,重送的動作會發生在重送計時器的時間到期時,或是已經有 3 個重複的ACK 抵達時。 請注意: 在最新的實作中,重送的動作會發生在重送計時器的時間到期時,或是已經有 3 個重複的ACK 抵達時。
TCP 不會針對 ACK 區段去設定重送計時器。 請注意: TCP 不會針對 ACK 區段去設定重送計時器。
資料有可能不照順序抵達,並且被接收端的TCP 暫存起來,但是 TCP 保證不會有亂序的區段被傳遞到上層的程序。 請注意: 資料有可能不照順序抵達,並且被接收端的TCP 暫存起來,但是 TCP 保證不會有亂序的區段被傳遞到上層的程序。
請注意: 接收端的 TCP 只會傳遞 已經排序好的資料給上層的程序。
可能會產生死結 ( deadlock ) 的情況。 請注意: 如果回應的遺失沒有適當的處理, 可能會產生死結 ( deadlock ) 的情況。
12.8 壅塞控制 壅塞控制 ( congestion control ) 會提到關於壅塞的控制方法與技巧,讓網路的負載能被控制在其容量之內。 本節所討論的主題包括: 網路效能 壅塞控制機制 TCP 中的壅塞控制
請注意: 在慢速啟動的演算法中,壅塞窗口的大小會以指數方式成長,直到它到達某個門檻值為止。
請注意: 在壅塞避免的演算法中,壅塞窗口的大小會以加法的方式成長,直到壅塞被偵測到為止。
請注意: 大部份的實作對壅塞偵測有不同的反應: 如果是透過時間到期所偵測,會開始於一個新的慢速啟動階段。 如果是透過三次回應所偵測,會開始於一個新的壅塞避免階段。
12.9 TCP 計時器 大部份 TCP 的實作使用了四種計時器來維持運作的平穩性。 本節所討論的主題包括: 重送計時器 持續計時器 維持存活計時器 等候結束計時器
在TCP中,同一時間下只能處理一個 RTT 的量測程序。 請注意: 在TCP中,同一時間下只能處理一個 RTT 的量測程序。
範例10 讓我們來看一個假設的範例,圖12.38 說明了某條連線的一部份,圖中顯示連線的建立及部份的資料傳輸階段。 當SYN區段傳送出去時,RTTM、RTTS、及 RTTD 尚未有值,而 RTO 的值被設定為 6 秒。這時變數的值如下所示: RTO = 6 當SYN+ACK區段抵達,其 RTTM 被量測後為 1.5 秒,其變數的值如下所示: RTTM = 1.5 RTTS = 1.5 RTTD = 1.5 / 2 = 0.75 RTO = 1.5 + 4 . 0.75 = 4.5
範例10 (續) 當第一個資料區段傳送出去時,一個新的 RTT 量測程序被啟動。請注意,當傳送端傳送ACK區段時並不會啟動 RTT 量測程序,因為它不會消耗序號也不會啟動計時器。第二個資料區段也不會啟動 RTT 量測程序,因為已經有一個量測程序正在進行中。最後一個ACK區段的抵達被用來計算下一個 RTTM 的值。儘管最後一個ACK區段是用來回應兩個資料區段 ( 累計式 ),它的抵達完成了第一個區段之RTTM的值。其變數的值如下所示: RTTM = 2.5 RTTS = 7/8 (1.5) + 1/8 (2.5) = 1.625 RTTD = 3/4 (0.75) + 1/4 |1.625 − 2.5| = 0.78 RTO = 1.625 + 4 (0.78) = 4.74
請注意: TCP 在計算新的 RTO 值的時候, 並不會考慮一個重送區段的 RTT 值。
範例11 圖12.39 延續先前的範例,有一個重送的情況發生,並使用Karn演算法。 圖中的第一個區段傳送之後卻遺失了。在 4.74 秒之後 RTO 計時器的時間到期。 此區段會被重送,並且其 RTO 計時器被設定為 9.48 秒 ( 先前 RTO 值的兩倍 )。 這一次在時間到期之前就收到ACK區段了。 我們會等到傳送新的區段及接收 ACK 才會再一次的計算RTO 的值 ( Karn演算法 )。
12.10 選項 TCP 標頭最多包含 40 位元組的選項 ( option ) 資訊,這些選項運送額外的資訊給目的端或是做為選項對齊的功能。
請注意: EOP 只能被使用一次。
請注意: NOP 可以被使用超過一次。
請注意: MSS 的值於連線建立時被決定, 並且在這條連線運作期間都不會改變。
窗口調整係數的值只能在連線建立時被決定, 並且在這條連線運作期間都不會改變。 請注意: 窗口調整係數的值只能在連線建立時被決定, 並且在這條連線運作期間都不會改變。
請注意: 時間戳記選項的其中一項應用就是用來 計算往返時間( RTT ) 的值。
範例12 圖12.46 說明了某一端計算往返時間的範例。如果我們要計算另一端的 RTT,則每件事都要翻轉過來。 傳送端很簡單地將系統時間 ( 例如:從午夜算起的秒數值 ) 填到第一個和第二個區段之時間戳記數值欄位中。 當一個回應區段抵達 ( 第三個區段 ),它可以將目前系統時間的值減掉時間戳記回應欄的值,就可以找到目前範例中的 RTT = 12。 接收端的運作就比較複雜一點,它必須記錄最近一個已傳送的回應號碼 ( 12000 )。 接下一張投影片
範例12 (續) 當第一個區段抵達,它包含了位元組編號從 12000 到 12099 的資料,而第一個位元組的編號和 lastack 的值相同,所以它將時間戳記的值 ( 4720 ) 複製到 tsrecent 變數中,而 lastack 的值依然保持 12000 ( 沒有新的回應被傳送 )。 當第二個區段抵達,因為此區段並沒有包含 lastack 所指定的位元組資料,所以其時間戳記的值會被忽略。當接收端決定要傳送一個累計式的回應 ( 回應編號為 12200 ) 時,它會將 lastack 的值改成 12200,並且將 tsrecent 的值填入時間戳記回應欄位。而 tsrecent 的值並不會改變,一直到被一個帶有12200位元組資料的新區段 ( 下一個區段 ) 所取代為止。 接下一張投影片
範例12 (續) 請注意,如同範例所示,RTT 的計算是傳送第一個區段與接收到第三個區段之間的時間差。
時間戳記選項也可用來防止序號回歸( Protection Against Wrapped Sequence Numbers, PAWS )。 請注意: 時間戳記選項也可用來防止序號回歸( Protection Against Wrapped Sequence Numbers, PAWS )。
範例13 讓我們來看一下SACK選項是如何被使用來條列出亂序的區塊。 在圖12.48 中,某一端點接收到 5 個資料區段。 但是,第 3、4、5 個區段是亂序抵達的區段,在第二個區段和第三個區段之間有一個間隙,在第四個區段和第五個區段之間也有一個間隙。 接下一張投影片
範例13 (續) 一個 ACK 加上一個 SACK 就可以很明確的告知傳送端目前的情況。ACK 的值為 2001,代表傳送端不需要再關心位元組編號從 1 到 2000 的資料了。 SACK 有兩個區塊,第一個區塊告知位元組編號從 4001 到 6000 的資料已經亂序抵達了,第二個區塊告知位元組編號從 8001 到 9000 的資料已經亂序抵達了。 這也代表位元組編號從 2001 到 4000 的資料以及位元組編號從 6001 到 8000 的資料已經遺失或被丟棄了,傳送端只需要重新傳送這些位元組資料即可。
範例14 在圖12.49 的範例中,說明如何使用 ACK 和 SACK 來偵測重複的區段。在這種情況下,我們擁有一些亂序的區段 ( 在一個區塊中 ) 及一個重複的區段。 為了同時去顯示亂序及重複的資料,SACK 使用第一個區塊來顯示重複的資料,使用其它的區塊來顯示亂序的資料。 請注意,只有第一個區塊可以用來顯示重複的區塊。一個很直覺的問題,那就是當傳送端接收到 ACK 和 SACK 的值,它怎麼知道第一個區塊是否是用來顯示重複的區塊 ( 將這個範例與前一個範例相比較 )。 答案是如果在第一個區塊中的位元組資料早已經被回應時,當然這個區塊就是一個重複的區塊。
範例15 在圖12.50 的範例中,展示如果在亂序的區段中有一個區段被重複時會發生什麼情況。 在這個範例中,有一個區段 ( 4001:5000 ) 被重複了,SACK 選項先宣告這一個被重複的區段,然後才宣告亂序的區塊。 但是這一次重複的區塊尚未被回應,所以我們無法使用前一個範例的方法來判斷第一個區塊是表示重複的區塊,但是因為這個區塊是亂序區塊中的一部份 ( 4001:5000 區塊屬於 4001:6000 區塊中的一部份 ),所以傳送端可以知道它定義的是一個重複的區塊。
12.11 TCP套件 我們介紹一個經過簡化,僅呈現其骨幹結構的TCP套件。 TCP 套件包含了一個稱為傳輸控制區塊 ( transmission control block, TCB ) 的表格、一組計時器、及三個程式模組。 本節所討論的主題包括: 傳輸控制區塊 計時器 主要模組 輸入處理模組 輸出處理模組