Socket中的TIME_WAIT狀態(tài) 在高并發(fā)短連接的server端,當server處理完client的請求后立刻closesocket此時會出現(xiàn)time_wait狀態(tài)然后如果client再并發(fā)2000個連接,此時部分連接就連接不上了,用linger強制關閉可以解決此問題,但是linger會導致數(shù)據(jù)丟失,linger值為0時是強制關閉,無論并發(fā)多少多能正常連接上,如果非0會發(fā)生部分連接不上的情況!(可調用setsockopt設置套接字的linger延時標志,同時將延時時間設置為0。) TCP/IP的RFC文檔。TIME_WAIT是TCP連接斷開時必定會出現(xiàn)的狀態(tài)。 是無法避免掉的,這是TCP協(xié)議實現(xiàn)的一部分。 在WINDOWS下,可以修改注冊表讓這個時間變短一些 time_wait的時間為2msl,默認為4min. 你可以通過改變這個變量: TcpTimedWaitDelay 把它縮短到30s
TCP要保證在所有可能的情況下使得所有的數(shù)據(jù)都能夠被投遞。當你關閉一個socket時,主動關閉一端的socket將進入TIME_WAIT狀態(tài),而被動關閉一方則轉入CLOSED狀態(tài),這的確能夠保證所有的數(shù)據(jù)都被傳輸。當一個socket關閉的時候,是通過兩端互發(fā)信息的四次握手過程完成的,當一端調用close()時,就說明本端沒有數(shù)據(jù)再要發(fā)送了。這好似看來在握手完成以后,socket就都應該處于關閉CLOSED狀態(tài)了。但這有兩個問題,首先,我們沒有任何機制保證最后的一個ACK能夠正常傳輸,第二,網(wǎng)絡上仍然有可能有殘余的數(shù)據(jù)包(wandering duplicates),我們也必須能夠正常處理。 .. 通過正確的狀態(tài)機,我們知道雙方的關閉過程如下
圖
假設最后一個ACK丟失了,服務器會重發(fā)它發(fā)送的最后一個FIN,所以客戶端必須維持一個狀態(tài)信息,以便能夠重發(fā)ACK;如果不維持這種狀態(tài),客戶端在接收到FIN后將會響應一個RST,服務器端接收到RST后會認為這是一個錯誤。如果TCP協(xié)議能夠正常完成必要的操作而終止雙方的數(shù)據(jù)流傳輸,就必須完全正確的傳輸四次握手的四個節(jié),不能有任何的丟失。這就是為什么socket在關閉后,仍然處于 TIME_WAIT狀態(tài),因為他要等待以便重發(fā)ACK。 . 如果目前連接的通信雙方都已經調用了close(),假定雙方都到達CLOSED狀態(tài),而沒有TIME_WAIT狀態(tài)時,就會出現(xiàn)如下的情況。現(xiàn)在有一個新的連接被建立起來,使用的IP地址與端口與先前的完全相同,后建立的連接又稱作是原先連接的一個化身。還假定原先的連接中有數(shù)據(jù)報殘存于網(wǎng)絡之中,這樣新的連接收到的數(shù)據(jù)報中有可能是先前連接的數(shù)據(jù)報。為了防止這一點,TCP不允許從處于TIME_WAIT狀態(tài)的socket建立一個連接。處于TIME_WAIT狀態(tài)的socket在等待兩倍的MSL時間以后(之所以是兩倍的MSL,是由于MSL是一個數(shù)據(jù)報在網(wǎng)絡中單向發(fā)出到認定丟失的時間,一個數(shù)據(jù)報有可能在發(fā)送圖中或是其響應過程中成為殘余數(shù)據(jù)報,確認一個數(shù)據(jù)報及其響應的丟棄的需要兩倍的MSL),將會轉變?yōu)镃LOSED狀態(tài)。這就意味著,一個成功建立的連接,必然使得先前網(wǎng)絡中殘余的數(shù)據(jù)報都丟失了。 由于TIME_WAIT狀態(tài)所帶來的相關問題,我們可以通過設置SO_LINGER標志來避免socket進入TIME_WAIT狀態(tài),這可以通過發(fā)送RST而取代正常的TCP四次握手的終止方式。但這并不是一個很好的主意,TIME_WAIT對于我們來說往往是有利的。
|