咱們只知道在四次揮手的過程當中,先發起關閉的一方會進入TIME_WAIT狀態,爲何會出現TIME_WAIT狀態以及TIME_WAIT狀態過多,是什麼緣由?shell
1 出現的場景
客戶端在TCP創建鏈接對外提供服務的過程當中,每一個連接會佔用一個本地端口,如在高併發的狀況下,TIME_WAIT狀態過多,勢必會佔用大量的端口,端口又有限,以至於耗盡端口,因此會出現偶爾連接的上,偶爾斷開的狀況編程
這麼多的TIME_WAIT哪裏來的呢?先複習下四次揮手網絡
四次揮手併發
[FIN_WAIT1] :FIN_WAIT1和FIN_WAIT2均爲等待對方的FIN報文。二者區別爲,當SOCKET在ESTABLISHED狀態時,想主動關閉鏈接從而想對方發送FIN報文,此時進入FIN_WAIT1狀態。當收到ACK報文進入FIN_WAIT2狀態。socket
[FIN_WAIT_2]:此狀態下的socket實際上表示半鏈接的狀態。什麼是半鏈接,是一方想要關閉鏈接,另外一方說稍等下,我還有點數據給你tcp
[FIN_WAIT] :表示收到了對方的FIN報文,併發送出了ACK報文,就等2MSL後便可回到CLOSED可用狀態了ide
[CLOSE_WAIT] : 反過來讀比較好,WAIT_CLOSE即「等待關閉」。在被動關閉鏈接狀況下,在已經接收到FIN,可是尚未發送本身的FIN的時刻,鏈接處於CLOSE_WAIT狀態。高併發
[LAST_ACK] :被動關閉乙方發送FIN後,等待對方的ACK,收到ACK即進入CLOSED狀態優化
在TCP/IP協議棧中,假設主機A想要進行連接終止操做,因而發送FIN報文給主機B,主機B收到從而進入CLOSE_WAIT狀態併發送ACK做爲應答,同時主機B會告訴應用程序也要關閉操做,因而發送FIN報文。主機A收到FIN報文發送ACK表示收到並進入TIME_WAITui
在Linux系統中有一個字段,名稱爲TCP_TIME_WAIT_LEN,其數值爲60s,也就是須要在TIME_WAIT階段停留60s
2 TIME_WAIT什麼做用
從上圖咱們知道TIME_WAIT事後還有CLOSE狀態,爲何不直接進入CLOSED狀態,而是要過一會呢?
第一點,在TIME_WAIT後,爲了確保ACK能讓被動方接收並輔助其關閉。假設這樣的狀況
若是主機A的ACK報文傳輸失敗,那麼在TCP/IP協議棧設計中,主機B會重傳FIN報文,可是此時主機A沒有維護好TIME_WAIT狀態而是CLOSED狀態,此時主機A只好發送RST,從而被動關閉失敗。
第二點,爲了讓就鏈接的重複節點在網絡中天然消失。怎麼理解?
咱們知道,在網絡傳輸的過程當中,總會由於各類故障致使報文不能準時到達目的地。如今咱們假設使用[源IP,源端口,目的IP,目的端口]表明鏈接A,在通訊的過程當中,連接A由於某種緣由中斷,暫時迷路,從而建立了相似於A的鏈接B,但是迷路的鏈接A此時到達了,勢必就會對TCP通訊產生影響。因此設置了2MSL,足夠的時間讓兩個方向的分組都消失,使得下一個新的鏈接不會出現舊的鏈接請求報文
3 TIME_WAIT哪些危害
內存資源佔用
端口占用。端口資源有限,通常可開啓端口爲32768~61000,能夠經過修改net.ipv4.ip_local_port_range指定,若是TIME_WAIT太多將沒法創建鏈接
你能夠經過下面命令查看當前TIME_WAIT數量
這裏爲何是28233呢,取決於內核參數net.ipv4.ip_local_range
由於端口範圍是一個閉區間,因此實際可用的端口數量是:
shell> echo $((61000-32768+1)) 28233
4 TIME_WAIT如何優化
暴力執法------net.ipv4.tcp_max_tw_buckets
一旦TIME_WAIT狀態過多就重置,方法是使用sysctl將系統值減少,太粗魯不推薦
調低 TCP_TIMEWAIT_LEN
瞭解內核編譯便可操做
SO_LINGER設置,不推薦,由於它直接跳過TIME_WAIT
int setsockopt(int sockfd, int level, int optname, const void *optval,socklen_t optlen);
調整tcp_tw_recycle
咱們先看看RFC1323中怎麼描述的
An additional mechanism could be added to the TCP, a per-hostcache of the last timestamp received from any connection.This value could then be used in the [PAWS] mechanism to rejectold duplicate segments from earlier incarnations of theconnection, if the timestamp clock can be guaranteed to haveticked at least once since the old connection was open. This would require that the TIME-WAIT delay plus the RTT togethermust be at least one tick of the sender’s timestamp clock.Such an extension is not part of the proposal of this RFC.
net.ipv4.tcp_tw_reuse 複用鏈接
使用這個選項有個前提,須要打開TCP時間戳的支持net.ipv4.tcp_time stamps=1,在RFC1323中,爲了保證TCP的高可用,引入了兩個4字節的時間戳選項,用於記錄 TCP 發送方的當前時間戳和從對端接收到的最新時間戳。這就有意思了,以前說的2MSL就不存在了,由於若是重複的數據包會由於時間戳的過時而被丟棄
只適用於鏈接發起方(C/S 模型中的客戶端),這裏爲何強調是客戶端,咱們看看源碼;
其調用路徑僅僅出如今tcp_v4_connect->inet_hash_connect->__inet_check_established->twsk_unique->twsk_unique。 也就是說tcp_tw_reuse僅在TCP套接字做爲客戶端,調用connect時起做用。做爲服務端不多主動發起連接,因此對於服務端而言不用打開此選項
對應的 TIME_WAIT 狀態的鏈接建立時間超過 1 秒才能夠被複用。
最後引用一下W. Richard Stevens在《UNIX網絡編程》的一句話
The TIME_WAIT state is our friend and is there to help us (i.e., to let old duplicate segments expire in the network). Instead of trying to avoid the state, we should understand it.
譯者:存在即合理,勇敢面對,而不是逃避。