TCP的11種狀態

TCP的11種狀態

TCP三次握手創建鏈接

Tcp頭部服務器

 

 

六個標誌位中,咱們要用到三個:網絡

 

SYN:SYN= 1 表示這是一個鏈接請求或鏈接接受報文。在創建鏈接時用來進行同步序號(我的理解是,在創建鏈接的時候,提醒對方記錄本方的起始序號)。當SYN=1而ACK=0時,代表這是一個鏈接請求報文段。對方如果贊成創建鏈接,則應響應的報文段中使SYN=一、ACK=1。所以SYN=1表示該報文是一個鏈接請求報文或者是一個鏈接請求接收報文。併發

ACK:確認號只有在該位設置爲1的時候才生效,當該位爲0是表示確認號無效。TCP規定,在TCP鏈接創建後全部傳送的數據報文段ACK都必須設置爲1。tcp

FIN:當 FIN = 1 時,代表此報文段的發送方的數據已經發送完畢,並要求釋放鏈接。blog

 

此外咱們還須要用到序號和確認號:ip

 

序號:佔4個字節,它的範圍在0-2^32-1,序號隨着通訊的進行不斷的遞增,當達到最大值的時候從新回到0在開始遞增。TCP是面向字節流的,在一個TCP鏈接中傳送的字節流中的每個字節都按照順序編號。整個要傳送的字節流的起始號必須在鏈接創建時設置。首部中的序列號字段指的是本報文段所發送的數據的第一個字節的序號。例如,一個報文序號是301,而攜帶的數據共有100字節。則表示本次報文中的序號是301,下一個報文的序號是401.重複一下,每個報文的序號是該報文包含的字節中第一個字節的編號。資源

 

確認號:佔4個字節,確認號,是對下一個想要接受的字節的指望,這裏隱式確認了對上一個數據包的成功接收。如上例,在成功接收了序號爲301的數據包,想要接收下一個數據包由於上個數據包包含100字節,因此此時的確認號應該是401,表示但願接收下一個序號是401的數據包。同步

三次握手過程:服務器端

 

 

過程描述:請求

首先由Client發出請求鏈接即 SYN=1 ACK=0  (請看頭字段的介紹),TCP規定SYN=1時不能攜帶數據,但要消耗一個序號,所以聲明本身的序號是 seq=x。

而後 Server 進行回覆確認,即 SYN=1 ACK=1 seq=y,ack=x+1。

再而後 Client 再進行一次確認,但不用SYN 了,這時即爲 ACK=1, seq=x+1,ack=y+1。

 

爲何要進行三次握手(兩次確認):

爲何A還要發送一側確認呢?這主要是爲了防止已失效的鏈接請求報文忽然又傳送到了B,於是產生錯誤。

所謂「已失效的鏈接請求報文段」是這樣產生的。考慮一種正常狀況。A發出鏈接請求,但因鏈接請求丟失而未收到確認。因而A再次重傳一次鏈接請求。後來收到了確認創建了鏈接。數據傳輸完畢後,就釋放了鏈接。A供發送了兩個鏈接請求的報文段,其中第一個丟失,第二個到達了B。沒有「已失效的鏈接請求報文段」。

現假定出現一種異常狀況,即A發出的第一個鏈接請求報文段並無丟失,而是在某些網絡節點長時間滯留了,以至延誤到鏈接釋放之後的某個時間纔到B。原本這是一個已失效的報文段。可是B收到此失效的鏈接請求報文段後,就誤認爲是A有發出一次新的鏈接請求。因而就向A發出確認報文段,贊成創建鏈接。假定不採用三次握手,那麼只要B發出確認,新的鏈接就創建了。

因爲如今A並無發出創建鏈接的請求,所以不會理睬B的確認,也不會向B發送數據。但B卻覺得新的運輸鏈接已經創建了,並一直等待A發來數據。B的許多資源就這樣拜拜浪費了。

採用三次握手的辦法能夠防止上述現象的發生。例如在剛纔的狀況下,A不會向B的確認發出確認。B因爲收不到確認,就知道A並無要求創建鏈接。

另外一種解釋:

這個問題的本質是, 信道不可靠, 可是通訊雙發須要就某個問題達成一致. 而要解決這個問題, 不管你在消息中包含什麼信息, 三次通訊是理論上的最小值. 因此三次握手不是TCP自己的要求, 而是爲了知足"在不可靠信道上可靠地傳輸信息"這一需求所致使的. 請注意這裏的本質需求,信道不可靠, 數據傳輸要可靠. 三次達到了, 那後面你想接着握手也好, 發數據也好, 跟進行可靠信息傳輸的需求就不要緊了. 所以,若是信道是可靠的, 即不管何時發出消息, 對方必定能收到, 或者你不關心是否要保證對方收到你的消息, 那就能像UDP那樣直接發送消息就能夠了」。這可視爲對「三次握手」目的的另外一種解答思路。

 

四次揮手關閉鏈接

 

 

當客戶A 沒有東西要發送時就要釋放 A 這邊的鏈接,A會發送一個報文(沒有數據),其中 FIN 設置爲1,  服務器B收到後會給應用程序一個信,這時A那邊的鏈接已經關閉,即A再也不發送信息(但仍可接收信息)。  A收到B的確認後進入等待狀態,等待B請求釋放鏈接, B數據發送完成後就向A請求鏈接釋放,也是用FIN=1 表示, 而且用 ack = u+1(如圖), A收到後回覆一個確認信息,並進入 TIME_WAIT 狀態, 等待 2MSL 時間。

l  爲何要等待呢?

l  爲了防止這種狀況:A接到B的釋放鏈接請求後會發送一個確認信息,可是若是這個確認信息丟了,也就是B沒有收到確認釋放鏈接,那麼B就會重發一個釋放鏈接請求,這時候A還處於TIME_WAIT狀態,因此會再次發送一個確認信息。

l  Q2爲何TIME_WAIT 狀態還須要等2*MSL秒以後才能返回到CLOSED 狀態呢?

l  A2由於雖然雙方都贊成關閉鏈接了,並且握手的4個報文也都發送完畢,按理能夠直接回到CLOSED 狀態(就比如從SYN_SENT 狀態到ESTABLISH 狀態那樣),可是咱們必須假想網絡是不可靠的,你沒法保證你最後發送的ACK報文必定會被對方收到,就是說對方處於LAST_ACK 狀態下的SOCKET可能會由於超時未收到ACK報文,而重發FIN報文,因此這個TIME_WAIT 狀態的做用就是用來重發可能丟失的ACK報文。

 

11種狀態

 

 

 

簡單解釋:

l  CLOSED:初始狀態,表示TCP鏈接是「關閉着的」或「未打開的」。

l  LISTEN :表示服務器端的某個SOCKET處於監聽狀態,能夠接受客戶端的鏈接。

l  SYN_RCVD :表示服務器接收到了來自客戶端請求鏈接的SYN報文。在正常狀況下,這個狀態是服務器端的SOCKET在創建TCP鏈接時的三次握手會話過程當中的一箇中間狀態,很短暫,基本上用netstat很難看到這種狀態,除非故意寫一個監測程序,將三次TCP握手過程當中最後一個ACK報文不予發送。當TCP鏈接處於此狀態時,再收到客戶端的ACK報文,它就會進入到ESTABLISHED 狀態。

l  SYN_SENT :這個狀態與SYN_RCVD 狀態相呼應,當客戶端SOCKET執行connect()進行鏈接時,它首先發送SYN報文,而後隨即進入到SYN_SENT 狀態,並等待服務端的發送三次握手中的第2個報文。SYN_SENT 狀態表示客戶端已發送SYN報文。

l  ESTABLISHED :表示TCP鏈接已經成功創建。

l  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看到。

l  FIN_WAIT_2 :上面已經解釋了這種狀態的由來,實際上FIN_WAIT_2狀態下的SOCKET表示半鏈接,即有一方調用close()主動要求關閉鏈接。注意:FIN_WAIT_2 是沒有超時的(不像TIME_WAIT 狀態),這種狀態下若是對方不關閉(不配合完成4次揮手過程),那這個 FIN_WAIT_2 狀態將一直保持到系統重啓,愈來愈多的FIN_WAIT_2 狀態會致使內核crash。

l  TIME_WAIT :表示收到了對方的FIN報文,併發送出了ACK報文。 TIME_WAIT狀態下的TCP鏈接會等待2*MSL(Max Segment Lifetime,最大分段生存期,指一個TCP報文在Internet上的最長生存時間。每一個具體的TCP協議實現都必須選擇一個肯定的MSL值,RFC 1122建議是2分鐘,但BSD傳統實現採用了30秒,Linux能夠cat /proc/sys/net/ipv4/tcp_fin_timeout看到本機的這個值),而後便可回到CLOSED 可用狀態了。若是FIN_WAIT_1狀態下,收到了對方同時帶FIN標誌和ACK標誌的報文時,能夠直接進入到TIME_WAIT狀態,而無須通過FIN_WAIT_2狀態。(這種狀況應該就是四次揮手變成三次揮手的那種狀況)

l  CLOSING :這種狀態在實際狀況中應該不多見,屬於一種比較罕見的例外狀態。正常狀況下,當一方發送FIN報文後,按理來講是應該先收到(或同時收到)對方的ACK報文,再收到對方的FIN報文。可是CLOSING 狀態表示一方發送FIN報文後,並無收到對方的ACK報文,反而卻也收到了對方的FIN報文。什麼狀況下會出現此種狀況呢?那就是當雙方几乎在同時close()一個SOCKET的話,就出現了雙方同時發送FIN報文的狀況,這是就會出現CLOSING 狀態,表示雙方都正在關閉SOCKET鏈接。

l  CLOSE_WAIT :表示正在等待關閉。怎麼理解呢?當對方close()一個SOCKET後發送FIN報文給本身,你的系統毫無疑問地將會迴應一個ACK報文給對方,此時TCP鏈接則進入到CLOSE_WAIT狀態。接下來呢,你須要檢查本身是否還有數據要發送給對方,若是沒有的話,那你也就能夠close()這個SOCKET併發送FIN報文給對方,即關閉本身到對方這個方向的鏈接。有數據的話則看程序的策略,繼續發送或丟棄。簡單地說,當你處於CLOSE_WAIT 狀態下,須要完成的事情是等待你去關閉鏈接。

l  LAST_ACK :當被動關閉的一方在發送FIN報文後,等待對方的ACK報文的時候,就處於LAST_ACK 狀態。當收到對方的ACK報文後,也就能夠進入到CLOSED 可用狀態了。

 

CLOSING狀態:

 

 

相關文章
相關標籤/搜索