最近測試環境server因爲須要與大量的後臺server交互,今天忽然發現有大量的close_wait產生,因而仔細研究了一下:
若是咱們的服務器程序處於CLOSE_WAIT狀態的話,說明套接字是被動關閉的!
由於若是是CLIENT端主動斷掉當前鏈接的話,那麼雙方關閉這個TCP鏈接共須要四個packet:
1.Client -> FIN -> Server
2.Client <- ACK <- Server 這時候Client端處於FIN_WAIT_2狀態;而Server 程序處於CLOSE_WAIT狀態。
3.Client <- FIN <- Server 這時Server 發送FIN給Client,Server 就置爲LAST_ACK狀態。
4.Client -> ACK -> Server Client迴應了ACK,那麼Server 的套接字纔會真正置爲CLOSED狀態。
Server 程序處於CLOSE_WAIT狀態,而不是LAST_ACK狀態,說明尚未發FIN給Client,那麼多是在關閉鏈接以前還有許多數據要發送或者其餘事要作,
致使沒有發這個FIN packet。
一般來講,一個CLOSE_WAIT會維持至少2個小時的時間(這個時間外網服務器一般會作調整,要否則太危險了)。
若是有個流氓特意寫了個程序,給你形成一堆的CLOSE_WAIT,消耗你的資源,那麼一般是等不到釋放那一刻,系統就已經解決崩潰了。
只能經過修改一下TCP/IP的參數,來縮短這個時間:修改tcp_keepalive_*系列參數有助於解決這個問題。
可是實際上,仍是主要是由於咱們的程序代碼有問題,一般是以下問題:
好比被動關閉的是客戶端。。。
當對方調用closesocket的時候,你的程序正在
C代碼
int nRet = recv(s,....);
if (nRet == SOCKET_ERROR)
{
// closesocket(s);
return FALSE;
}
不少人就是忘記了那句closesocket,這種代碼太常見了。
個人理解,當主動關閉的一方發送FIN到被動關閉這邊後,被動關閉這邊的 TCP立刻迴應一個ACK過去,同時向上面應用程序提交一個ERROR,
致使上面的SOCKET的send或者recv返回SOCKET_ERROR,正常狀況下,若是上面在返回SOCKET_ERROR後調用了 closesocket,那麼被動關閉的者一方的TCP就會發送一個FIN過去,本身的狀態就變遷到LAST_ACK. 服務器
close_wait socket
TCP狀態變遷 tcp