TCP連線狀態和time_wait

myownstars發表於2013-06-28

TCP連線狀態

LISTEN      偵聽來自遠方的TCP埠的連線請求

SYN-SENT:再傳送連線請求後等待匹配的連線請求

SYN-RECEIVED:再收到和傳送一個連線請求後等待對方對連線請求的確認

ESTABLISHED:代表一個開啟的連線

FIN-WAIT-1:等待遠端TCP連線中斷請求,或先前的連線中斷請求的確認

FIN-WAIT-2:從遠端TCP等待連線中斷請求

CLOSE-WAIT:等待從本地使用者發來的連線中斷請求

CLOSING:等待遠端TCP對連線中斷的確認

LAST-ACK:等待原來的發向遠端TCP的連線中斷請求的確認

TIME-WAIT:等待足夠的時間以確保遠端TCP接收到連線中斷請求的確認

CLOSED:沒有任何連線狀態

 

TCP建立連線需要3次握手,而關閉需要4次握手

 

客戶端的狀態可以用如下的流程來表示:

             CLOSED->SYN_SENT->ESTABLISHED->FIN_WAIT_1->FIN_WAIT_2->TIME_WAIT->CLOSED

以上流程是在程式正常的情況下應該有的流程,

在建立連線時,當客戶端收到SYN報文的ACK以後,客戶端就開啟了資料互動地連線;

結束連線則通常是客戶端主動結束的,客戶端結束應用程式以後,需要經歷FIN_WAIT_1FIN_WAIT_2等狀態;

 

伺服器的狀態可以用如下的流程來表示:

             CLOSED->LISTEN->SYN收到->ESTABLISHED->CLOSE_WAIT->LAST_ACK->CLOSED

 在建立連線的時候,伺服器端是在第三次握手之後才進入資料互動狀態,而關閉連線則是在關閉連線的第二次握手以後,而關閉以後還要等待客戶端給出最後的ACK包才能進入初始的狀態。

 

TCP有一個特別的概念叫做half-close,這個概念是說,TCP的連線是全雙工(可以同時傳送和接收)連線,因此在關閉連線的時候,必須關閉傳和送兩個方向上的連線。客戶機給伺服器一個FIN1TCP報文,然後伺服器返回給客戶端一個確認ACK報文,並且傳送一個FIN報文,當客戶機回覆ACK報文後(四次握手),連線就結束;

 

FIN_WAIT_2狀態

       這就是著名的半關閉的狀態了,這是在關閉連線時,客戶端和伺服器兩次握手之後的狀態。在這個狀態下,應用程式還有接受資料的能力,但是已經無法傳送資料,但是也有一種可能是,客戶端一直處於FIN_WAIT_2狀態,而伺服器則一直處於WAIT_CLOSE狀態,而直到應用層來決定關閉這個狀態

 

 

TIME_WAIT

在這四次握手狀態中,有一個特別要注意的狀態TIME_WAIT。這個狀態是主動關閉方在收到被關閉方的FIN後會處於並長期(2MSL時間,根據具體的實現不同,這個值會不同,在RFC 1122建議MSL=2分鐘)處於的一個狀態。也就是大約1-4分鐘,然後由作業系統自動回收並將TCP連線設為CLOSED初始狀態

 

TIME_WAIT等待狀態,又叫做2MSL狀態,說的是在TIME_WAIT2傳送了最後一個ACK資料包以後,要進入TIME_WAIT狀態,這個狀態是防止最後一次握手的資料包沒有傳送到對方那裡而準備的(注意這不是四次握手,這是第四次握手的保險狀態)。這個狀態在很大程度上保證了雙方都可以正常結束,但是,問題也來了。

由於插口的2MSL狀態(插口是IP和埠對的意思,socket),使得應用程式在2MSL時間內是無法再次使用同一個插口的,對於客戶程式還好一些,但是對於服務程式,例如httpd,它總是要使用同一個埠來進行服務,而在2MSL時間內,啟動httpd就會出現錯誤(插口被使用)。為了避免這個錯誤,伺服器給出了一個平靜時間的概念,這是說在2MSL時間內,雖然可以重新啟動伺服器,但是這個伺服器還是要平靜的等待2MSL時間的過去才能進行下一次連線。

 

 

 

TIME_WAIT的影響

當某個連線的一端處於TIME_WAIT狀態時,該連線將不能再被使用。事實上,對於我們比較有現實意義的是,這個埠將不能再被使用。

某個埠處於TIME_WAIT狀態(其實應該是這個連線)時,這意味著這個TCP連線並沒有斷開(完全斷開),那麼,如果你bind這個埠,就會失敗。

對於伺服器而言,如果伺服器突然crash掉了,那麼它將無法再2MSL內重新啟動,因為bind會失敗。解決這

個問題的一個方法就是設定socketSO_REUSEADDR選項。這個選項意味著你可以重用一個地址。

 

http://kerry.blog.51cto.com/172631/105233/

mysql為例, 大量的TIME_WAIT有可能阻塞新連線的建立;

App每次退出mysql時應呼叫mysql.close()

 

 

如何避免TCP_WAIT

檢視當前TCP連線狀態

[oracle@ ~]$ netstat -n | awk '/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}'

TIME_WAIT 51

ESTABLISHED 402

 

對應大量TCP連線,設定如下引數

Tcp_tw_reuse=1 重用TIME-WAIT socket

Tcp_tw_recycle=1 –快速回收TIME-WAIT socket

Tcp_fin_timeout –當伺服器關閉socket後其保留為FIN-WAIT-2的時間

 

 

 

 

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/15480802/viewspace-765059/,如需轉載,請註明出處,否則將追究法律責任。

相關文章