1、TCP鏈接創建(正常狀況)
三次握手 (three-way handshake) html
- 請求端發送一個SYN段指明客戶端打算創建鏈接的服務器端口,以及初始序號 (ISN)
- 服務器發回包含服務器的初始序號的SYN報文段做爲應答。同時,將確認序號設置爲客戶端的ISN加1以對客戶的SYN報文段加以確認。一個SYN將佔用一個序號。
- 客戶端將確認序號設置爲服務器的ISN加1以對服務器的SYN報文段進行確認。
發送第一個SYN字段的一端執行主動打開 (active open)。接收SYN併發送下一個SYN的一端執行被動打開 (passive open)。 算法
2、鏈接終止協議(正常狀況)
終止鏈接須要4次握手,這是因爲TCP的半關閉 (halfclose)形成的。既然一個TCP鏈接是全雙工的,所以每一個方向必須單獨地進行關閉。
收到一個FIN只意味着這一方向上沒有數據流動。一個TCP鏈接在收到一個FIN之後仍能發送數據,雖然實際應用中不多這麼作。正常的關閉過程以下所示。 服務器
 網絡
注意,一個FIN將佔用一個序號。 併發
3、最大報文段長度 (MSS)
最大報文段長度表示TCP傳往另外一端的最大塊數據的長度。當一個鏈接創建時,鏈接的雙方都要通告各自的MSS。
MSS位於TCP首部的「選項」字段。通常來講,若是沒有分段,MSS越大越好,這樣能夠減小TCP和IP首部的出現,能夠提升網絡利用率。
通常,將MSS值設置爲外出接口上的MTU長度減去固定的IP首部和TCP首部長度。
MSS讓主機限制另外一端發送數據報的長度,主機也能控制它發送數據報的長度。這樣將使以較小MTU鏈接到一個網絡上的主機避免分段。
若是兩端的主機都鏈接到以太網上,可是中間網絡採用296的MTU,也將出現分段。使用路徑上的MTU發現機制是關於這個問題的惟一解決方法。socket
4、TCP的半關閉
TCP提供了鏈接的一端在結束它的發送之後還能接收來自另外一端數據的能力,叫作半關閉。
 ide
使用半關閉可讓客戶通知服務器,客戶端已經完成了它的數據傳輸,但仍要接收來自服務器的數據。注意服務器收到來自客戶端的FIN之後,會嚮應用程序交付EOF。post
5、TCP狀態變遷圖
 ui
- 上圖中,粗的實線箭頭表示正常的客戶端狀態變遷;粗的虛線箭頭表示正常的服務器狀態變遷。
- 兩個致使進入
ESTABLISHED
狀態的變遷對應打開一個鏈接,兩個致使從ESTABLISHED
鏈接離開的變遷對應關閉一個鏈接。
 spa
5.1 2MSL等待狀態
TIME_WAIT
狀態也成爲2MSL狀態。每一個TCP實現都必須選擇一個報文段的最大生存時間MSL (Maximum Segment Lifetime)。它是任何報文段被丟棄前在網絡內的最長時間。
當TCP執行一個主動關閉,併發回最後一個ACK,該鏈接必須在TIME_WAIT
狀態停留時間爲2倍的MSL,這樣可讓TCP再次發送最後的ACK以防這個ACK丟失(另外一端超時並重發最後的FIN)。
所以這個TCP鏈接在2MSL等待期間,定義這個鏈接的插口對不能再被使用,這個鏈接只能在2MSL結束後才能再被使用。
鏈接處於2MSL狀態時,任何遲到的報文都被丟棄。由於處於2MSL等待的、由該接口對定義的鏈接在這段時間內不能被再用。
若是咱們終止一個程序,並當即從新啓動這個程序,那麼這個程序不能重用相同的本地端口,由於正處於2MSL狀態。
5.2 平靜時間 (Quiet Time) 的概念
若是處於2MSL等待端口的主機(通常是客戶端)crash了,在MSL時間內重啓,並當即使用crash前仍處於2MSL的socket pair創建一個新的鏈接。那麼crash前從這個鏈接發出而遲到的報文段會被錯誤地當作屬於重啓後新鏈接的報文段。
TCP在重啓動後的MSL秒內不能創建任何鏈接,這稱之爲平靜時間。但只有極少的實現版遵照這一原則,由於大多數主機重啓時間都比MSL秒要長。
5.3 FIN_WAIT_2
狀態
本地: 已經發出了FIN,也收到了另外一端發送的ACK,等待另外一端發來的FIN。
若是另外一端一直不發送FIN,而且一直處於CLOSE_WAIT
狀態,那麼本地一直處於FIN_WAIT_2
狀態。
6、復位報文段
不管什麼時候一個報文段發往基準的鏈接出現錯誤,TCP都會發送一個復位報文段。(「基準的鏈接」,即socket pair定義的鏈接)。
6.1 到不存在的端口的鏈接請求
即當鏈接請求到達時,目的端口沒有進程在監聽。對於UDP,產生一個ICMP端口不可達信息;對於TCP,使用復位。
6.2 異常終止一個鏈接
終止一個鏈接的正常方式是一方發送FIN,這種狀況成爲有序釋放 (orderly release)。 也有可能發送一個復位報文段,而不是FIN來中途釋放一個鏈接,成爲異常釋放 (abortive release)。
異常終止一個鏈接有兩個有特色 (feature):
- 丟棄任何待發數據,並當即發送復位報文段
- RST的接收方會去人另外一端執行的是異常關閉仍是正常關閉。
RST報文段不會致使另外一端產生任何響應,另外一端根本不進行確認。收到RST的一方將終止該鏈接,並通知應用層鏈接復位。
6.3 檢測半打開鏈接
若是一方已經關閉或異常終止鏈接而另外一方還不知道,這樣子的TCP鏈接成爲半打開 (Half-Open)的。
常見緣由是當客戶主機忽然掉電。例如當關閉客戶主機的電源時,已經再也不有向服務器的數據,服務器將永遠不知道客戶程序已經消失了。客戶主機重啓後,和服務器從新創建新的鏈接。這樣子會致使服務器主機中產生許多半打開的TCP鏈接(可使用TCP的keepalive
選項使TCP的一端發現另外一端已經消失)。
當主機成功重啓之後,會丟失復位前鏈接的全部信息。若是收到一個半打開的鏈接發送的TCP數據,TCP處理原則是接收方以復位做爲應答。
7、同時打開
兩個應用程序同時彼此執行主動打開,稱爲同時打開 (simultaneous open)。

一個同時打開的鏈接須要交換須要交換4個報文段,比正常的三次握手多一個。沒有任何一端稱爲客戶或服務器,由於每一端既是客戶又是服務器。

8、同時關閉
雙方同時執行主動關閉,叫作同時關閉 (simultaneous close)。

執行同時關閉時,雙方的狀態變化均以下所示。

9、TCP服務器設計
當一個新的鏈接請求到達服務器時,服務器接受這個請求,並調用一個新的進程(線程)來處理這個新的客戶請求。
9.1 限定本地IP地址
若是指明一個IP地址做爲服務器,那麼僅會監聽來自指定網卡的數據。
9.2 限定遠端IP地址
RFC 793指定容許一個服務器在執行被動打開時,可指明遠端插口(等待一個特定的客戶執行主動打開),也可不指明遠端插口(等待任何用戶)。
遺憾的是,大多實現規定服務器必須不指明遠端插口,而等待鏈接請求的到來,而後檢查客戶端IP地址和端口號。
9.3 呼入鏈接請求隊列
在伯克利的TCP實現中採用下面規則
- 正在等待鏈接請求的一端有一個固定長度的鏈接隊列。該隊列中的鏈接已經被TCP接受(三次握手已經完成),但還沒被應用層接受。
TCP接受一個鏈接-->將其放入這個隊列
應用層接受鏈接-->將其從隊列中移除 - 應用層指明該隊列的長度,這個值成爲積壓值 (backlog)。
- 當一個鏈接請求 (SYN) 到達時,TCP使用一個算法,根據當前隊列中的鏈接數來肯定是否接受這個鏈接。
- 對於新的鏈接請求,若是該TCP監聽的端點的鏈接隊列中還有空間,TCP模塊將對SYN進行確認並完成鏈接的創建。
- 對於新的鏈接請求,若是鏈接隊列中沒有空間,TCP將不理會收到的SYN,也不發回任何報文段。
若是應用層不能及時接受已被TCP接受的鏈接,那麼這些鏈接可能佔滿整個鏈接隊列,客戶的主動打開最終會超時。