TCP 狀態變化
關閉socket分為主動關閉(Active closure)和被動關閉(Passive closure)兩種情況。前者是指有本地主機主動發起的關閉;而后者則是指本地主機檢測到遠程主機發起關閉之后,作出回應,從而關閉整個連接。將關閉部分的狀態轉移摘出來,就得到了下圖:
發生原因
通過圖上,我們來分析,什么情況下,連接處于CLOSE_WAIT狀態呢?
在被動關閉連接情況下,在已經接收到FIN,但是還沒有發送自己的FIN的時刻,連接處于CLOSE_WAIT狀態。
通常來講,CLOSE_WAIT狀態的持續時間應該很短,正如SYN_RCVD狀態。但是在一些特殊情況下,就會出現連接長時間處于CLOSE_WAIT狀態的情況。
出現大量close_wait的現象,主要原因是某種情況下對方關閉了socket鏈接,但是我方忙與讀或者寫,沒有關閉連接。代碼需要判斷socket,一旦讀到0,斷開連接,read返回負,檢查一下errno,如果不是AGAIN,就斷開連接。
more:
起初每個socket都是CLOSED狀態,當客戶端初使化一個連接,他發送一個SYN包到服務器,客戶端進入SYN_SENT狀態。服務器接收到SYN包,反饋一個SYN-ACK包,客戶端接收后返饋一個ACK包客戶端變成ESTABLISHED狀態,如果長時間沒收到SYN-ACK包,客戶端超時進入CLOSED狀態。
當服務器綁定并監聽某一端口時,socket的狀態是LISTEN,當客戶企圖建立連接時,服務器收到一個SYN包,并反饋SYN-ACK包。服務器狀態變成SYN_RCVD,當客戶端發送一個ACK包時,服務器socket變成ESTABLISHED狀態。
當一個程序在ESTABLISHED狀態時有兩種圖徑關閉它,***是主動關閉,第二是被動關閉。如果你要主動關閉的話,發送一個FIN包。當你的程序closesocket或者shutdown(標記),你的程序發送一個FIN包到peer,你的socket變成FIN_WAIT_1狀態。peer反饋一個ACK包,你的socket進入FIN_WAIT_2狀態。如果peer也在關閉連接,那么它將發送一個FIN包到你的電腦,你反饋一個ACK包,并轉成TIME_WAIT狀態。 TIME_WAIT狀態又號2MSL等待狀態。MSL意思是***段生命周期(Maximum+Segment+Lifetime)表明一個包存在于網絡上到被丟棄之間的時間。每個IP包有一個TTL(time_to_live),當它減到0時則包被丟棄。每個路由器使TTL減一并且傳送該包。當一個程序進入TIME_WAIT狀態時,他有2個MSL的時間,這個充許TCP重發***的ACK,萬一***的ACK丟失了,使得FIN被重新傳輸。在2MSL等待狀態完成后,socket進入CLOSED狀態。
被動關閉:當程序收到一個FIN包從peer,并反饋一個ACK包,于是程序的socket轉入CLOSE_WAIT狀態。因為peer已經關閉了,所以不能發任何消息了。但程序還可以。要關閉連接,程序自已發送給自已FIN,使程序的TCP socket狀態變成LAST_ACK狀態,當程序從peer收到ACK包時,程序進入CLOSED狀態。