TCP/IP詳解學習筆記(10)-TCP鏈接的創建與停止

TCP是一個面向鏈接的協議,因此在鏈接雙方發送數據以前,都須要首先創建一條鏈接。這和前面講到的協議徹底不一樣。前面講的全部協議都只是發送數據而已,大多數都不關心發送的數據是否是送到,UDP尤爲明顯,從編程的角度來講,UDP編程也要簡單的多----UDP都不用考慮數據分片。 服務器

書中用telnet登錄退出來解釋TCP協議鏈接的創建和停止的過程,能夠看到,TCP鏈接的創建能夠簡單的稱爲三次握手,而鏈接的停止則能夠叫作四次握手網絡

1.鏈接的創建

在創建鏈接的時候,客戶端首先向服務器申請打開某一個端口(用SYN段等於1的TCP報文),而後服務器端發回一個ACK報文通知客戶端請求報文收到,客戶端收到確認報文之後再次發出確認報文確認剛纔服務器端發出的確認報文(繞口麼),至此,鏈接的創建完成。這就叫作三次握手。若是打算讓雙方都作好準備的話,必定要發送三次報文,並且只須要三次報文就能夠了。 併發

能夠想見,若是再加上TCP的超時重傳機制,那麼TCP就徹底能夠保證一個數據包被送到目的地。 socket

2.結束鏈接

TCP有一個特別的概念叫作half-close,這個概念是說,TCP的鏈接是全雙工(能夠同時發送和接收)鏈接,所以在關閉鏈接的時候,必須關閉傳和送兩個方向上的鏈接。客戶機給服務器一個FIN爲1的TCP報文,而後服務器返回給客戶端一個確認ACK報文,而且發送一個FIN報文,當客戶機回覆ACK報文後(四次握手),鏈接就結束了。 學習

3.最大報文長度

在創建鏈接的時候,通訊的雙方要互相確認對方的最大報文長度(MSS),以便通訊。通常這個SYN長度是MTU減去固定IP首部和TCP首部長度。對於一個以太網,通常能夠達到1460字節。固然若是對於非本地的IP,這個MSS可能就只有536字節,並且,若是中間的傳輸網絡的MSS更佳的小的話,這個值還會變得更小。 spa

4.TCP的狀態遷移圖

書P182頁給出了TCP的狀態圖,這是一個看起來比較複雜的狀態遷移圖,由於它包含了兩個部分---服務器的狀態遷移和客戶端的狀態遷移,若是從某一個角度出發來看這個圖,就會清晰許多,這裏面的服務器和客戶端都不是絕對的,發送數據的就是客戶端,接受數據的就是服務器。 .net

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和端口號碼,服務器能夠很輕鬆的區別出不一樣的會話,來進行數據的分發。

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

相關文章
相關標籤/搜索