1. 程式人生 > >TCP/IP詳解學習筆記(10)-TCP連線的建立與中止

TCP/IP詳解學習筆記(10)-TCP連線的建立與中止

TCP是一個面向連線的協議,所以在連線雙方傳送資料之前,都需要首先建立一條連線。這和前面講到的協議完全不同。前面講的所有協議都只是傳送資料而已,大多數都不關心傳送的資料是不是送到,UDP尤其明顯,從程式設計的角度來說,UDP程式設計也要簡單的多----UDP都不用考慮資料分片。

書中用telnet登陸退出來解釋TCP協議連線的建立和中止的過程,可以看到,TCP連線的建立可以簡單的稱為三次握手,而連線的中止則可以叫做四次握手

1.連線的建立

在建立連線的時候,客戶端首先向伺服器申請開啟某一個埠(用SYN段等於1的TCP報文),然後伺服器端發回一個ACK報文通知客戶端請求報文收到,客戶端收到確認報文以後再次發出確認報文確認剛才伺服器端發出的確認報文(繞口麼),至此,連線的建立完成。這就叫做三次握手。如果打算讓雙方都做好準備的話,一定要傳送三次報文,而且只需要三次報文就可以了。

可以想見,如果再加上TCP的超時重傳機制,那麼TCP就完全可以保證一個數據包被送到目的地。

2.結束連線

TCP有一個特別的概念叫做half-close,這個概念是說,TCP的連線是全雙工(可以同時傳送和接收)連線,因此在關閉連線的時候,必須關閉傳和送兩個方向上的連線。客戶機給伺服器一個FIN為1的TCP報文,然後伺服器返回給客戶端一個確認ACK報文,並且傳送一個FIN報文,當客戶機回覆ACK報文後(四次握手),連線就結束了。

3.最大報文長度

在建立連線的時候,通訊的雙方要互相確認對方的最大報文長度(MSS),以便通訊。一般這個SYN長度是MTU減去固定IP首部和TCP首部長度。對於一個乙太網,一般可以達到1460位元組。當然如果對於非本地的IP,這個MSS可能就只有536位元組,而且,如果中間的傳輸網路的MSS更佳的小的話,這個值還會變得更小。

4.TCP的狀態遷移圖

書P182頁給出了TCP的狀態圖,這是一個看起來比較複雜的狀態遷移圖,因為它包含了兩個部分---伺服器的狀態遷移和客戶端的狀態遷移,如果從某一個角度出發來看這個圖,就會清晰許多,這裡面的伺服器和客戶端都不是絕對的,傳送資料的就是客戶端,接受資料的就是伺服器。

4.1.客戶端應用程式的狀態遷移圖

客戶端的狀態可以用如下的流程來表示:

CLOSED->SYN_SENT->ESTABLISHED->FIN_WAIT_1->FIN_WAIT_2->TIME_WAIT->CLOSED

以上流程是在程式正常的情況下應該有的流程,從書中的圖中可以看到,在建立連線時,當客戶端收到SYN報文的ACK以後,客戶端就打開了資料互動地連線。而結束連線則通常是客戶端主動結束的,客戶端結束應用程式以後,需要經歷FIN_WAIT_1,FIN_WAIT_2等狀態,這些狀態的遷移就是前面提到的結束連線的四次握手。

4.2.伺服器的狀態遷移圖

伺服器的狀態可以用如下的流程來表示:

CLOSED->LISTEN->SYN收到->ESTABLISHED->CLOSE_WAIT->LAST_ACK->CLOSED

在建立連線的時候,伺服器端是在第三次握手之後才進入資料互動狀態,而關閉連線則是在關閉連線的第二次握手以後(注意不是第四次)。而關閉以後還要等待客戶端給出最後的ACK包才能進入初始的狀態。

4.3.其他狀態遷移

書中的圖還有一些其他的狀態遷移,這些狀態遷移針對伺服器和客戶端兩方面的總結如下

  1. LISTEN->SYN_SENT,對於這個解釋就很簡單了,伺服器有時候也要開啟連線的嘛。
  2. SYN_SENT->SYN收到,伺服器和客戶端在SYN_SENT狀態下如果收到SYN資料報,則都需要傳送SYN的ACK資料報並把自己的狀態調整到SYN收到狀態,準備進入ESTABLISHED
  3. SYN_SENT->CLOSED,在傳送超時的情況下,會返回到CLOSED狀態。
  4. SYN_收到->LISTEN,如果受到RST包,會返回到LISTEN狀態。
  5. SYN_收到->FIN_WAIT_1,這個遷移是說,可以不用到ESTABLISHED狀態,而可以直接跳轉到FIN_WAIT_1狀態並等待關閉。

4.4.2MSL等待狀態

書中給的圖裡面,有一個TIME_WAIT等待狀態,這個狀態又叫做2MSL狀態,說的是在TIME_WAIT2傳送了最後一個ACK資料報以後,要進入TIME_WAIT狀態,這個狀態是防止最後一次握手的資料報沒有傳送到對方那裡而準備的(注意這不是四次握手,這是第四次握手的保險狀態)。這個狀態在很大程度上保證了雙方都可以正常結束,但是,問題也來了。

由於插口的2MSL狀態(插口是IP和埠對的意思,socket),使得應用程式在2MSL時間內是無法再次使用同一個插口的,對於客戶程式還好一些,但是對於服務程式,例如httpd,它總是要使用同一個埠來進行服務,而在2MSL時間內,啟動httpd就會出現錯誤(插口被使用)。為了避免這個錯誤,伺服器給出了一個平靜時間的概念,這是說在2MSL時間內,雖然可以重新啟動伺服器,但是這個伺服器還是要平靜的等待2MSL時間的過去才能進行下一次連線。

4.5.FIN_WAIT_2狀態

這就是著名的半關閉的狀態了,這是在關閉連線時,客戶端和伺服器兩次握手之後的狀態。在這個狀態下,應用程式還有接受資料的能力,但是已經無法傳送資料,但是也有一種可能是,客戶端一直處於FIN_WAIT_2狀態,而伺服器則一直處於WAIT_CLOSE狀態,而直到應用層來決定關閉這個狀態。

5.RST,同時開啟和同時關閉

RST是另一種關閉連線的方式,應用程式應該可以判斷RST包的真實性,即是否為異常中止。而同時開啟和同時關閉則是兩種特殊的TCP狀態,發生的概率很小。

6.TCP伺服器設計

前面曾經講述過UDP的伺服器設計,可以發現UDP的伺服器完全不需要所謂的併發機制,它只要建立一個數據輸入佇列就可以。但是TCP不同,TCP伺服器對於每一個連線都需要建立一個獨立的程序(或者是輕量級的,執行緒),來保證對話的獨立性。所以TCP伺服器是併發的。而且TCP還需要配備一個呼入連線請求佇列(UDP伺服器也同樣不需要),來為每一個連線請求建立對話程序,這也就是為什麼各種TCP伺服器都有一個最大連線數的原因。而根據源主機的IP和埠號碼,伺服器可以很輕鬆的區別出不同的會話,來進行資料的分發。

掌握本章的狀態遷移圖才是學習本章的關鍵。