1. 程式人生 > >TCP協議的學習(四)TCP四次揮手及解釋

TCP協議的學習(四)TCP四次揮手及解釋

發起斷開連線請求可以是客戶端也可以是伺服器,即主機1,主機2可以是客戶端也可以是伺服器。
ACK : TCP協議規定,只有ACK=1時有效,也規定連線建立後所有傳送的報文的ACK必須為1。
FIN (finis)即完,終結的意思, 用來釋放一個連線。當 FIN = 1 時,表明此報文段的傳送方的資料已經發送完畢,並要求釋放連線。
傳送序列號:Sequence Number
確認序列號:Acknowledgment Number

FIN_WAIT_1:表示等待對方的FIN報文。當SOCKET在ESTABLISHED狀態時,它想主動關閉連線,向對方傳送了FIN報文,此時該SOCKET進入到FIN_WAIT_1 狀態
FIN_WAIT_2:也表示等待對方的FIN報文。FIN_WAIT_2狀態下的SOCKET,表示半連線,也即有一方要求close連線,但另外還告訴對方,我暫時還有點資料需要傳送給你,稍後再關閉連線。
CLOSE_WAIT: 這種狀態的含義其實是表示在等待關閉。你回覆一個ACK給對方,並進入CLOSE_WAIT狀態。接下來就是檢視你是否還有資料要傳送給對方,如果沒有,就可以close這個socket,併發送FIN給對方,即關閉連線。
CLOSING:表示主機1給主機2傳送FIN後,並沒有收到主機2迴應的ACK,而收到了主機2傳送的FIN。表示雙方同時close一個socket,出現同時傳送FIN現象。
LAST_ACK: 傳送FIN報文後,等待對方的ACK報文,當收到ACK報文後,進入到CLOSED狀態。
TIME_WAIT: 表示收到了對方的FIN報文,併發送出了ACK確認,等2MSL後即可回到CLOSED可用狀態了。如果FIN_WAIT_1狀態下,收到了對方同時帶FIN標誌和ACK標誌的報文時,可以直接進入到TIME_WAIT狀態。

這裡寫圖片描述

第一次揮手:主機1向主機2,傳送FIN報文段,表示關閉資料傳送,並主機1進入FIN_WAIT_1狀態,表示沒有資料要傳輸了
第二次揮手:主機2收到FIN報文段後進入CLOSE_WAIT狀態(被動關閉),然後傳送ACK確認,表示同意你關閉請求了,主機到主機的資料鏈路關閉,主機進入FIN_WAIT_2狀態
第三次揮手:主機2等待主機1傳送完資料,傳送FIN到主機1請求關閉,主機2進入LAST_ACK狀態
第四次揮手:主機1收到主機2傳送的FIN後,回覆ACK確認到主機2,主機1進入TIME_WAIT狀態。主機2收到主機1的ACK後就關閉連線了,狀態為CLOSED。主機1等待2MSL,仍然沒有收到主機2的回覆,說明主機2已經正常關閉了,主機1關閉連線。

孤兒連線
連續停留在FIN_WAIT2狀態可能發生,客戶端執行半關閉狀態後,未等伺服器關閉連線就直接退出了,此時客戶端連線由核心接管。Linux為防止孤兒連線長時間存在核心中,定義了兩個變數指定孤兒連線數目和生存時間。

為什麼要四次揮手而不是三次呢?
當主機2傳送ACK確認主機1的FIN時,並不代表主機2的資料傳送完畢,主機1傳送完FIN處於半關閉狀態(不能傳送資料,但可以接收資料),所以要等待主機2的資料傳送完畢後,發出FIN關閉連線請求時,主機2才進入CLOSED狀態,主機1再ACK確認關閉進入CLOSE狀態。

為什麼TIME_WAIT 狀態要等2MSL才進入CLOSED狀態?


MSL(Maximum Segment Lifetime):報文最大生存時間,是任何報文段被丟棄前在網路內的最長時間。當主機1回覆主機2的FIN後,等待(2-4分鐘),即使兩端的應用程式結束。

如果主機1直接進入CLOSED狀態,由於IP協議不可靠性或網路問題,導致主機1最後發出的ACK報文未被主機2接收到,那麼主機2在超時後繼續向主機1重新發送FIN,而主機1已經關閉,那麼找不到向主機1傳送FIN的連線,主機2這時收到RST並把錯誤報告給高層,不符合TCP協議的可靠性特點。
如果主機1直接進入CLOSED狀態,而主機2還有資料滯留在網路中,當有一個新連線的埠和原來主機2的相同,那麼當原來滯留的資料到達後,主機1認為這些資料是新連線的。等待2MSL確保本次連線所有資料消失。

TIME_WAIT狀態過多會佔用大量的埠號,處理方法:
修改核心引數
儘可能被動關閉連線
將長連線改為短連線

close和shutdown
只要TCP棧的讀緩衝裡還有未讀取(read)資料,則呼叫close時會直接向對端傳送RST
close把描述字的引用計數減1,僅在該計數變為0的時候才關閉套介面。而使用shutdown可以不管引用計數的值是多少都能激發TCP的正常連線終止序列,即傳送FIN。
close終止資料傳送的兩個方向讀和寫。
shutdown函式進行關閉某一方向的操作。比如,有時我們只是需要告訴對方資料傳送完畢,只需要關閉資料傳送的一個通道,但還是要接受對方發過來的資料。