一直以來有許多讀者朋友對TCP的傳輸連接建立和釋放過程不是很理解,而這又是幾乎網絡認證中必考的知識點,包括軟考、CCNA\CCNP、H3CNA\H3CNE等,為此再把筆者年度巨作,廣受好評的——《深入理解計算機網絡》書中的相關內容摘出來與大家分享。本書詳細內容及讀者評價可從這里了解:http://item.jd.com/11165825.html,http://product.dangdang.com/23166396.html(目前7折促銷中)
10.3.6 TCP傳輸連接建立
TCP是一個面向連接的傳輸層協議,所以無論哪一方向另一方發送數據之前,都必須先在雙方之間建立一條傳輸連接。本節將詳細討論一個TCP傳輸連接是如何建立的。
1. 單方主動連接的TCP連接建立過程
在TCP/IP協議體系結構中的TCP協議也是使用三次握手(three-way handshake)機制來建立傳輸連接的,這與在本章前面介紹的OSI/RM傳輸層為了避免重復連接而采取的三次握手機制是一樣的。具體流程如圖10-38所示,其實整體過程在上節的圖10-37中有全面的體現,這里僅單獨把TCP傳輸連接建立過程列出來。具體步驟如下:
(1)首先是服務器初始化的過程,從CLOSED(關閉)狀態開始通過順序調用SOCKET、BIND、LISTEN和ACCEPT原語創建Socket套接字,進入LISTEN(監聽)狀態,等待客戶端的TCP傳輸連接請求。
(2)客戶端最開始也是從CLOSED狀態開始調用SOCKET原語創建新的Socket套接字,然后在需要再調用CONNECT原語,向服務器發送一個將SYN字段置1(表示此為同步數據段)的數據段(假設初始序號為i),主動打開端口,進入到SYN SENT(已發送連接請求,等待對方確認)狀態。

圖10-38 TCP傳輸連接建立的三次握手過程
(3)服務器在收到來自客戶端的SYN數據段后,發回一個SYN字段置1(表示此為同步數據段),ACK字段置1(表示此為確認數據段),ack(確認號)=i+1的應答數據段(假設初始序號為j),被動打開端口,進入到SYN RCVD(已收到一個連接請求,但未進行確認)狀態。這里要注意的是確認號是i+1,而不是i,表示服務器希望接收的下一下數據段序號為i+1。
(4)客戶端在收到來自服務器的SYN+ACK數據段后,向服務器發送一個ACK=1(表示此為確認數據段),序號為i+1,ack=j+1的確認數據段,同時進入ESTABLISHED(連接建立)狀態,建立單向連接。要注意的是,此時序號為i+1,確認號為j+1,表示客戶端希望收到服務器的下一個數據段的序號j+1。
(5)服務器在收到客戶端的ACK數據段后,進入ESTABLISHED狀態,完成雙向連接的建立。
連接可以由任一方或雙方發起,一旦連接建立,數據就可以雙向對等地流動,而沒有所謂的主從關系。三次握手是連接兩端正確同步的充要條件,因為TCP建立在不可靠的分組傳輸服務之上,報文可能丟失、延遲、重復和亂序,因此協議必須使用超時和重傳機制。如果重傳的連接請求和原先的連接請求在連接正在建立時到達,或者當一個連接已經建立、使用和結束之后,某個延遲的連接請求才到達,就會出現問題。采用三次握手協議就可以解決這些問題。如客戶端發送的ACK數據段就是為了避免因網絡延遲而導致的重復連接,因為這時客戶端就可通過檢查ACK數據段中的確認號就可得知該連接請求是否已失效。
【經驗之談】對比圖10-38和本章前面的10.2.2節中的圖10-20以看出,總體上TCP傳輸連接的建立與OSI/RM中TP傳輸協議的傳輸連接建立過程既存在相似之處(如三次握手機制),又存在較大區別的。主要表現在:①在OSI/RM中,只有DT TPDU和ED TPDU才有序列號,所以在返回的確認類TPDU中是沒有TPDU序號的,所以在圖10-20中並沒有標注確認TPDU的序列號,而TCP傳輸連接中,每個數據段(無論是否攜帶數據)都有序列號,都需要標其對應的序列號;②因為在OSI/RM的傳輸協議中不同服務原語可以使用不同的特定類型TPDU,所以在OSI/RM的TPDU中不存在像TCP數據段中的ACK、SYN等之類的控制位,因為在TCP協議中所有數據段格式是一樣的,不同的只是不同類型的TCP數據段的這些字段的取值不同;③TCP傳輸連接中使用“確認號”字段與OSI/RM TPDU中的“YR-TU-NR”(你的TPDU序列號)字段的功能是完全一樣的,都是顯示對端希望接收的下一個數據段序列號,暗示該號碼前面的所有數據段均已正確接收。
2. 雙方同時主動連接的TCP連接建立過程
正常情況下,傳輸連接都是由一方主動發起的,但也有可能雙方同時主動發起連接,此時就會發生連接碰撞,最終只有一個連接能夠建立起來。因為所有連接都是由它們的端點進行標識的。如果第一個連接請求建立起一個由套接字(x,y)標識的連接,而第二個連接也建立了這樣一個連接,那么在TCP實體內部只有一個套接字表項。
當出現同時發出連接請求時,則兩端幾乎在同時發送一個SYN字段置1的數據段,並進入SYN_SENT狀態。當每一端收到SYN數據段時,狀態變為SYN_RCVD,同時它們都再發送SYN字段置1,ACK字段置1的數據段,對收到的SYN數據段進行確認。當雙方都收到對方的SYN+ACK數據段后,便都進入ESTABLISHED狀態。圖10-39顯示了這種同時發起連接的連接過程,但最終建立的是一個TCP連接,而不是兩個,這點要特別注意。
圖 10-39 同時發起連接的TCP連接建立流程
從圖中可以看出,一個雙方同時打開的傳輸連接需要交換4數據段,比正常的傳輸連接建立所進行的三次握手多交換一個數據段。此外要注意的是,此時我們沒有將任何一端稱為客戶或服務器,因為每一端既是客戶又是服務器。
10.3.7 TCP傳輸連接的釋放
TCP 連接建立起來后,就可以在兩個方向傳送數據流。當 TCP的網絡應用進程再沒有數據需要發送時,就可以發出關閉連接命令,釋放連接。TCP協議是通過發送FIN字段置1的數據段來作為關閉傳輸連接的命令,關閉本端數據流的,但是本端仍然還可以繼續接收來自對端的數據,直到對端也使用了同樣的方法關閉那個方向的數據流,這時整個雙方傳輸連接就徹底關閉了。
1. 單方主動關閉的TCP連接釋放過程
相對TCP傳輸連接建立的三次握手過程來說,TCP傳輸連接的釋放過程要稍微復雜一些,需要經過四次握手過程。這是因為TCP的半關閉(half-close)特性造成的,即因這一個TCP連接是全雙工(即數據在兩個方向上能同時傳遞),每個方向必須單獨地進行關閉。TCP傳輸連接關閉的原則是:當一方完成它的數據發送任務后就可以發送一個FIN字段置1的數據段來終止這個方向的數據發送;當另一端收到這個FIN數據段后,必須通知它的應用層“對端已經終止了那個方向的數據傳送”。而FIN數據段的發送是由應用層調用CLOSE服務原語的結果。TCP連接釋放的四次握手過程如圖10-40所示,具體描述如下:
(1)一開始,通信雙方都處於ESTABLISHED(連接建立)狀態。如果客戶端認為數據全部發送完了,想結束本次傳輸連接,則由應用層的對應應用進程調用CLOSE服務原語,然后向服務器發出一個FIN字段置1的數據段(假設此數據段的序號為m),客戶端進入FIN WAIT 1狀態,等待服務器的確認。
(2)服務器在收到客戶端發來的FIN數據段后,確認客戶端沒有新的數據要發送了,向客戶端發送一個ACK字段置1,確認號為m+1(假設此數據段序號為w,服務器與客戶端的數據段序號可以不一樣),表示前面的數據已全部收到了,然后進入到CLOSE WAIT(關閉等待)狀態。與此同時服務器的TCP實體通知對應的應用層進程,釋放從客戶機到服務器方向的傳輸連接,進入半關閉狀態。但此時服務器仍可以向客戶端發送數據段;客戶端也可接收來自服務器的數據。而且這可能要持續一段時間,直到服務器的數據也全部發送完。
圖10-40 TCP傳輸連接釋放的四次握手過程
(3)當客戶端收到服務器的ACK數據段后便進入到了FIN WAIT 2狀態,進一步等待服務器發出連接釋放的數據段。
(4)當服務器發送完全部的數據后,其對應的應用進程也會通知TCP實體釋放此方向的TCP傳輸連接,向客戶機發送FIN字段置1,ACK字段置1,ack=m+1(假設此時的數據段序號已變為w)的確認數據段。這時服務器進入LAST ACK(最后確認)狀態,等待客戶端的確認。
(5)客戶端在收到服務器的FIN+ACK數據段后,向服務器發送一個ACK字段置1,ack=w+1,序列號為m+1的數據段,進入到TIME WAIT狀態。但此時TCP連接還沒有釋放,必須等待2MSL時間(RFC 793建議設MSL為2分鍾)后,客戶端才進入到CLOSED狀態,徹底釋放了TCP連接。
(6)服務器在收到客戶端發來的ACK數據段后,也進入CLOSED狀態,徹底釋放連接。完成整個TCP傳輸連接釋放過程。
2. 雙方主動關閉的TCP連接釋放流程
與可以雙方同時建立TCP傳輸連接一樣,TCP傳輸連接關閉也可以由雙方同時主動進行(正常情況下都是由一方發送第一個FIN數據段進行主動連接關閉,另一方被動接受連接關閉),如圖10-41所示。具體描述如下:
圖10-41 同時主動關閉TCP連接的流程
當兩端對應的網絡應用層進程同時調用CLOSE原語,發送FIN數據段執行關閉命令時,兩端均從ESTABLISHED狀態轉變為FIN WAIT 1狀態。任意一方收到對端發來的FIN數據段后,其狀態均由FIN WAIT 1轉變到CLOSING狀態,並發送最后的ACK數據段。當收到最后的ACK數據段后,狀態轉變化TIME_WAIT,在等待2MSL后進入到CLOSED狀態,最終釋放整個TCP傳輸連接。