閱讀402 返回首頁    go 阿裏雲 go 技術社區[雲棲]


TCP詳解(三次握手/四次揮手詳解)

在一些防火牆或端口管理工具中經常會看到連接狀態為CLOSED CLOSE_WITE LAST_ACK等的進程, 雖然狀態就那麼很少的幾個, 而且看字麵意思也能猜個大概, 但沒做過Socket編程的朋友卻很少能準確的知道每種狀態的準確含義, 我也是經常把其中幾項搞混. 下麵把幾種狀態的說明整理了一下, 也許會對有的朋友有點用:

CLOSED 沒有使用這個套接字
LISTEN 套接字正在監聽入境連接
SYN_SENT 套接字正在試圖主動建立連接
SYN_RECEIVED 正在處於連接的初始同步狀態
ESTABLISHED 連接已建立
CLOSE_WAIT 遠程套接字已經關閉:正在等待關閉這個套接字
FIN_WAIT_1 套接字已關閉,正在關閉連接
CLOSING 套接字已關閉,遠程套接字正在關閉,暫時掛起關閉確認
LAST_ACK 遠程套接字已關閉,正在等待本地套接字的關閉確認
FIN_WAIT_2 套接字已關閉,正在等待遠程套接字關閉
TIME_WAIT 這個套接字已經關閉,正在等待遠程套接字的關閉傳送

 

 

服務端,端口的狀態變化

 

  先在本機(IP地址為:192.168.1.10)配置FTP服務,然後在其它計算機(IP地址為:192.168.1.1)訪問FTP服務,從TCPView看看端口的狀態變化。

 

  下麵黑體字顯示的是從TCPView中截取的部分。

 

  1、LISTENING狀態

 

  FTP服務啟動後首先處於偵聽(LISTENING)狀態。

  State顯示是LISTENING時表示處於偵聽狀態,就是說該端口是開放的,等待連接,但還沒有被連接。就像你房子的門已經敞開的,但還沒有人進來。

  從TCPView可以看出本機開放FTP的情況。它的意思是:程序inetinfo.exe開放了21端口,FTP默認的端口為21,可見在本機開放了FTP服務。目前正處於偵聽狀態。

  inetinfo.exe:1260 TCP 0.0.0.0:21 0.0.0.0:0 LISTENING 

 

  2、ESTABLISHED狀態

 

  現在從192.168.1.1這台計算機訪問一下192.168.1.10的FTP服務。在本機的TCPView可以看出端口狀態變為ESTABLISHED。

  ESTABLISHED的意思是建立連接。表示兩台機器正在通信。

  下麵顯示的是本機的FTP服務正在被192.168.1.1這台計算機訪問。

  inetinfo.exe:1260 TCP 192.168.1.10:21 192.168.1.1:3009 ESTABLISHED

  注意:處於ESTABLISHED狀態的連接一定要格外注意,因為它也許不是個正常連接。後麵我們要講到這個問題。

 

  3、 TIME_WAIT狀態

 

  現在從192.168.1.1這台計算機結束訪問192.168.1.10的FTP服務。在本機的TCPView可以看出端口狀態變為TIME_WAIT。

  TIME_WAIT的意思是結束了這次連接。說明21端口曾經有過訪問,但訪問結束了。

  [System Process]:0 TCP 192.168.1.10:21 192.168.1.1:3009 TIME_WAIT 

 

  4、小技巧

 

  a、可以telnet一個開放的端口,來觀察該端口的變化。比如看1025端口是開放的,在命令狀態(如圖1運行cmd)運行:

  telnet 192.168.1.10 1025

  b、從本機也可以測試,隻不過顯示的是本機連本機

  c、在Tcpview中雙擊連接可看出程序的位置,右鍵點擊該連接,選擇End Process即可結束該連接

  客戶端,端口的狀態變化

  客戶端口實際上就是從本機訪問其它計算機服務時打開的源端口,最多的應用是上網,下麵就以訪問www.baidu.com為例來看看端口開放以及狀態的變化情況。

 

  1、SYN_SENT狀態

 

  SYN_SENT狀態表示請求連接,當你要訪問其它的計算機的服務時首先要發個同步信號給該端口,此時狀態為SYN_SENT,如果連接成功了就變為ESTABLISHED,此時SYN_SENT狀態非常短暫。但如果發現SYN_SENT非常多且在向不同的機器發出,那你的機器可能中了衝擊波或震蕩波之類的病毒了。這類病毒為了感染別的計算機,它就要掃描別的計算機,在掃描的過程中對每個要掃描的計算機都要發出了同步請求,這也是出現許多SYN_SENT的原因。

  下麵顯示的是本機連接www.baidu.com網站時的開始狀態,如果你的網絡正常的,那很快就變為ESTABLISHED的連接狀態。

  IEXPLORE.EXE:2928 TCP 192.168.1.10:1035 202.108.250.249:80 SYN_SENT

 

  2、ESTABLISHED狀態

 

  下麵顯示的是本機正在訪問www.baidu.com網站。如果你訪問的網站有許多內容比如訪問www.yesky.com,那會發現一個地址有許多ESTABLISHED,這是正常的,網站中的每個內容比如圖片、flash等都要單獨建立一個連接。看ESTABLISHED狀態時一定要注意是不是IEXPLORE.EXE程序(IE)發起的連接,如果是EXPLORE.EXE之類的程序發起的連接,那也許是你的計算機中了木馬了。

  IEXPLORE.EXE:3120 TCP 192.168.1.10:1045 202.108.250.249:80 ESTABLISHED

  3、TIME_WAIT狀態

 

  如果瀏覽網頁完畢,那就變為TIME_WAIT狀態。

  [System Process]:0 TCP 192.168.1.10:4259 202.108.250.249:80 TIME_WAIT



1、建立連接協議(三次握手)

(1)客戶端發送一個帶SYN標誌的TCP報文到服務器。這是三次握手過程中的報文1。
(2) 服務器端回應客戶端的,這是三次握手中的第2個報文,這個報文同時帶ACK標誌和SYN標誌。因此它表示對剛才客戶端SYN報文的回應;同時又標誌SYN給客戶端,詢問客戶端是否準備好進行數據通訊。
(3) 客戶必須再次回應服務段一個ACK報文,這是報文段3。
2、連接終止協議(四次揮手)
   由於TCP連接是全雙工的,因此每個方向都必須單獨進行關閉。這原則是當一方完成它的數據發送任務後就能發送一個FIN來終止這個方向的連接。收到一個 FIN隻意味著這一方向上沒有數據流動,一個TCP連接在收到一個FIN後仍能發送數據。首先進行關閉的一方將執行主動關閉,而另一方執行被動關閉。
 (1) TCP客戶端發送一個FIN,用來關閉客戶到服務器的數據傳送(報文段4)。
 (2) 服務器收到這個FIN,它發回一個ACK,確認序號為收到的序號加1(報文段5)。和SYN一樣,一個FIN將占用一個序號。
 (3) 服務器關閉客戶端的連接,發送一個FIN給客戶端(報文段6)。
 (4) 客戶段發回ACK報文確認,並將確認序號設置為收到序號加1(報文段7)。
CLOSED: 這個沒什麼好說的了,表示初始狀態。
LISTEN: 這個也是非常容易理解的一個狀態,表示服務器端的某個SOCKET處於監聽狀態,可以接受連接了。
SYN_RCVD: 這個狀態表示接受到了SYN報文,在正常情況下,這個狀態是服務器端的SOCKET在建立TCP連接時的三次握手會話過程中的一個中間狀態,很短暫,基本上用netstat你是很難看到這種狀態的,除非你特意寫了一個客戶端測試程序,故意將三次TCP握手過程中最後一個ACK報文不予發送。因此這種狀態時,當收到客戶端的ACK報文後,它會進入到ESTABLISHED狀態。
SYN_SENT: 這個狀態與SYN_RCVD遙想唿應,當客戶端SOCKET執行CONNECT連接時,它首先發送SYN報文,因此也隨即它會進入到了SYN_SENT狀態,並等待服務端的發送三次握手中的第2個報文。SYN_SENT狀態表示客戶端已發送SYN報文。
ESTABLISHED:這個容易理解了,表示連接已經建立了。
FIN_WAIT_1: 這個狀態要好好解釋一下,其實FIN_WAIT_1和FIN_WAIT_2狀態的真正含義都是表示等待對方的FIN報文。而這兩種狀態的區別是:FIN_WAIT_1狀態實際上是當SOCKET在ESTABLISHED狀態時,它想主動關閉連接,向對方發送了FIN報文,此時該SOCKET即進入到FIN_WAIT_1狀態。而當對方回應ACK報文後,則進入到FIN_WAIT_2狀態,當然在實際的正常情況下,無論對方何種情況下,都應該馬上回應ACK報文,所以FIN_WAIT_1狀態一般是比較難見到的,而FIN_WAIT_2狀態還有時常常可以用netstat看到。
FIN_WAIT_2:上麵已經詳細解釋了這種狀態,實際上FIN_WAIT_2狀態下的SOCKET,表示半連接,也即有一方要求close連接,但另外還告訴對方,我暫時還有點數據需要傳送給你,稍後再關閉連接。
TIME_WAIT: 表示收到了對方的FIN報文,並發送出了ACK報文,就等2MSL後即可回到CLOSED可用狀態了。如果FIN_WAIT_1狀態下,收到了對方同時帶FIN標誌和ACK標誌的報文時,可以直接進入到TIME_WAIT狀態,而無須經過FIN_WAIT_2狀態。
CLOSING: 這種狀態比較特殊,實際情況中應該是很少見,屬於一種比較罕見的例外狀態。正常情況下,當你發送FIN報文後,按理來說是應該先收到(或同時收到)對方的ACK報文,再收到對方的FIN報文。但是CLOSING狀態表示你發送FIN報文後,並沒有收到對方的ACK報文,反而卻也收到了對方的FIN報文。什麼情況下會出現此種情況呢?其實細想一下,也不難得出結論:那就是如果雙方幾乎在同時close一個SOCKET的話,那麼就出現了雙方同時發送FIN報文的情況,也即會出現CLOSING狀態,表示雙方都正在關閉SOCKET連接。
CLOSE_WAIT: 這種狀態的含義其實是表示在等待關閉。怎麼理解呢?當對方close一個SOCKET後發送FIN報文給自己,你係統毫無疑問地會回應一個ACK報文給對方,此時則進入到CLOSE_WAIT狀態。接下來呢,實際上你真正需要考慮的事情是察看你是否還有數據發送給對方,如果沒有的話,那麼你也就可以close這個SOCKET,發送FIN報文給對方,也即關閉連接。所以你在CLOSE_WAIT狀態下,需要完成的事情是等待你去關閉連接。
LAST_ACK: 這個狀態還是比較容易好理解的,它是被動關閉一方在發送FIN報文後,最後等待對方的ACK報文。當收到ACK報文後,也即可以進入到CLOSED可用狀態了。
最後有2個問題的回答,我自己分析後的結論(不一定保證100%正確)
1、 為什麼建立連接協議是三次握手,而關閉連接卻是四次握手呢?
這是因為服務端的LISTEN狀態下的SOCKET當收到SYN報文的建連請求後,它可以把ACK和SYN(ACK起應答作用,而SYN起同步作用)放在一個報文裏來發送。但關閉連接時,當收到對方的FIN報文通知時,它僅僅表示對方沒有數據發送給你了;但未必你所有的數據都全部發送給對方了,所以你可以未必會馬上會關閉SOCKET,也即你可能還需要發送一些數據給對方之後,再發送FIN報文給對方來表示你同意現在可以關閉連接了,所以它這裏的ACK報文和FIN報文多數情況下都是分開發送的。
2、 為什麼TIME_WAIT狀態還需要等2MSL後才能返回到CLOSED狀態?

這是因為:雖然雙方都同意關閉連接了,而且握手的4個報文也都協調和發送完畢,按理可以直接回到CLOSED狀態(就好比從SYN_SEND狀態到ESTABLISH狀態那樣);但是因為我們必須要假想網絡是不可靠的,你無法保證你最後發送的ACK報文會一定被對方收到,因此對方處於LAST_ACK狀態下的SOCKET可能會因為超時未收到ACK報文,而重發FIN報文,所以這個TIME_WAIT狀態的作用就是用來重發可能丟失的ACK報文。



最後更新:2017-04-03 19:13:18

  上一篇:go 排序算法係列之二叉查找樹
  下一篇:go Android Http請求網絡模擬超時