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