在開始之前可以先了解一下 TCP三次握手
TCP四次揮手程序和狀態變遷
為什么揮手需要四次?
為什么TIME_WAIT等待的時間是2MSL?
等待2MSL的意義
TIME_WAIT狀態過多有什么危害?
如何解決TIME_WAIT狀態過多?

TCP四次揮手程序和狀態變遷

在斷開連接之前客戶端和服務器都處于ESTABLISHED狀態,雙方都可以主動斷開連接,以客戶端主動斷開連接為優,
第一次揮手:客戶端打算斷開連接,向服務器發送FIN報文(FIN標記位被設定為1,1表示為FIN,0表示不是),FIN報文中會指定一個序列號,之后客戶端進入FIN_WAIT_1狀態,
也就是客戶端發出連接釋放報文段(FIN報文),指定序列號seq = u,主動關閉TCP連接,等待服務器的確認,
第二次揮手:服務器收到連接釋放報文段(FIN報文)后,就向客戶端發送ACK應答報文,以客戶端的FIN報文的序列號 seq+1 作為ACK應答報文段的確認序列號ack = seq+1 = u + 1,
接著服務器進入CLOSE_WAIT(等待關閉)狀態,此時的TCP處于半關閉狀態(下面會說什么是半關閉狀態),客戶端到服務器的連接釋放,客戶端收到來自服務器的ACK應答報文段后,進入FIN_WAIT_2狀態,
第三次握手:服務器也打算斷開連接,向客戶端發送連接釋放(FIN)報文段,之后服務器進入LASK_ACK(最后確認)狀態,等待客戶端的確認,
服務器的連接釋放(FIN)報文段的FIN=1,ACK=1,序列號seq=m,確認序列號ack=u+1,
第四次握手:客戶端收到來自服務器的連接釋放(FIN)報文段后,會向服務器發送一個ACK應答報文段,以連接釋放(FIN)報文段的確認序號 ack 作為ACK應答報文段的序列號 seq,以連接釋放(FIN)報文段的序列號 seq+1作為確認序號ack,
之后客戶端進入TIME_WAIT(時間等待)狀態,服務器收到ACK應答報文段后,服務器就進入CLOSE(關閉)狀態,到此服務器的連接已經完成關閉,
客戶端處于TIME_WAIT狀態時,此時的TCP還未釋放掉,需要等待2MSL后,客戶端才進入CLOSE狀態,
由客戶端到服務器需要一個FIN和ACK,再由服務器到客戶端需要一個FIN和ACK,因此通常被稱為四次握手,
客戶端和服務器都可以主動關閉連接,只有率先請求關閉的一方才會進入TIME_WAIT(時間等待狀態),
為什么揮手需要四次?
這是由于TCP的半關閉(half-close)造成的,半關閉是指:TCP提供了連接的一方在結束它的發送后還能接受來自另一端資料的能力,通俗來說,就是不能發送資料,但是還可以接受資料,
TCP不允許連接處于半打開狀態時,就單向傳輸資料,因此完成三次握手后才可以傳輸資料(第三握手可以攜帶資料),
當連接處于半關閉狀態時,TCP是允許單向傳輸資料的,也就是說服務器此時仍然可以向客戶端發送資料,等服務器不再發送資料時,才會發送FIN報文段,同意現在關閉連接,
這一特性是由于TCP雙向通道互相獨立所導致的,也使得關閉連接必須經過四次握手,
可能有些人會有疑惑:為什么中間的ACK和FIN不可以像三次握手那樣合為一個報文段呢?
在socket網路編程中,執行close()方法會觸發內核發送FIN報文,什么時候呼叫close()方法,這是由用戶態決定的,假如服務器仍有大量資料等待處理,那么服務器會等資料處理完后,才呼叫close()方法,這個時間可能會很久,而ACK報文則是由系統內核來完成的,這個程序會很快,所以中間的ACK和FIN不能合為一個包,
為什么TIME_WAIT等待的時間是2MSL?
MSL(Maximum Segment LifeTime)是報文最大生成時間,它是任何報文在網路上存在的最長時間,超過這個時間的報文將被丟棄,
因為TCP協議是基于IP協議(位于IP協議的上一層),IP資料報中有限制其生存時間的TTL欄位,是IP資料報可以經過的最大路由器的個數,每經過處理它的路由,TTL就會減一,TTL為 0 時還沒有到達目的地的資料報將會被丟棄,同時發送 ICMP 報文通知源主機,
MSL的單位為時間,TTL的單位為跳轉數,所以MSL應該大于等于TTL變為0的時間,以確保報文已被丟棄,
TIME_WAIT等待的2MSL時間,可以理解為資料報一來一回所需要的最大時間,
2MSL時間是從客戶端接收到FIN后發送ACK開始計時的,如果在這個時間段內,服務器沒有收到ACK應答報文段,會重發FIN報文段,如果客戶端收到了FIN報文段,那么2MSL的時間將會被重置,如果在2MSL時間段內,沒有收到任何資料報,客戶端則會進入CLOSE狀態,
等待2MSL的意義
1.保證客戶端最后發送的ACK能夠到達服務器,幫助其正常關閉,
由于這個ACK報文段可能會丟失,使得處于LAST_ACK狀態的服務器得不到對已發送FIN報文段的確認,從而會觸發超時重傳,服務器會重發FIN報文段,客戶端能保證在2MSL時間內收到來自服務器的重傳FIN報文段,從而客戶端重新發送ACK應答報文段,并重置2MSL計數,
假如客戶端不等待2MSL就之間進入CLOSE狀態,那么服務器會一直處于LAST_ACK狀態,
當客戶端發起建立SYN報文段請求建立新的連接時,服務端會發送RST報文段給客戶端,連接建立的程序就會被終止,
2.防止已失效的連接請求報文段出現在本連接中,
TIME_WAIT等待的2MSL時間,確保本連接內所產生的所有報文段都從網路中消失,使下一個新的連接中不會出現這種舊的連接請求報文段,
TIME_WAIT狀態過多有什么危害?
只有主動發起斷開請求的一方才會進入TIME_WAIT狀態!
1.占用系統資源
2.socket的TIME_WAIT狀態結束之前,該socket占用的埠號將一直無法釋放,如果服務器TIME_WAIT狀態過多,占滿了所有埠資源,則會導致無法創建新的連接,
如何解決TIME_WAIT狀態過多?
最好的辦法是盡量讓客戶端主動斷開連接,除非遇到一些例外情況,如客戶端協議錯誤、客戶端超時等,
打開系統的TIME_WAIT重用和快速回收,
在Linux系統可以修改以下引數:
1.打開TCP對時間戳的支持,保持服務器與客戶端時間同步
net.ipv4.tcp_timestamps=1(默認即為 1)
2.修改net.ipv4.tcp_tw_reuse = 1,允許對處于TIME_WAIT的socket用于建立新的連接
net.ipv4.tcp_tw_reuse = 1 (默認為0)
修改TIME_WAIT連接狀態的上限值,超過上限值,處于TIME_WAIT狀態的socket將立刻被清除并列印警告資訊,
net.ipv4.tcp_max_tw_buckets = 18000,表示系統同時保持處于TIME_WAIT狀態的socket的最大數量,默認為18000,
可修改為更小值,
net.ipv4.tcp_max_tw_buckets = 6666
還有一個是修改短連接為長連接的方式(目前沒有學到),
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/356950.html
標籤:其他
上一篇:Qt - 網路編程
