TCP連接需三次握手才能建立,斷開連接則需要四次握手。
CLOSED->SYN_SENT->ESTABLISHED->FIN_WAIT_1->FIN_WAIT_2->TIME_WAIT->CLOSED
服務器TCP狀態遷移:
CLOSED->LISTEN->SYN收到->ESTABLISHED->CLOSE_WAIT->LAST_ACK->CLOSED


在三次握手協議中,服務器維護一個未連接隊列,該隊列為每個客戶端的SYN包(SYN=j)開設一個條目,該條目表明服務器已收到SYN包,並向客戶發 出確認,正在等待客戶的確認包。這些條目所標識的連接在服務器處於 SYN_RECV狀態,當服務器收到客戶的確認包時,刪除該條目,服務器進入ESTABLISHED狀態。
Backlog參數:
表示內核為相應套接字排隊的最大連接個數。僅對於backlog來說,我們需要取一個比較大的值以應對大量的服務請求。
服務器發送完SYN-ACK包,如果未收到客戶確認包,服務器進行首次重傳,等待一段時間仍未收到客戶確認包,進行第二次重傳,如果重傳次數超過系統規定的最大重傳次數,系統將該連接信息從半連接隊列中刪除。注意,每次重傳等待的時間不一定相同。
半連接存活時間:
是指半連接隊列的條目存活的最長時間,也即服務器從收到SYN包到確認這個報文無效的最長時間,該時間值是所有重傳請求包的最長等待時間總和。有時我們也稱半連接存活時間為Timeout時間、SYN_RECV存活時間。
二、關閉TCP連接:
由於TCP連接是全雙工的,因此每個方向都必須單獨進行關閉。這個原則是當一方完成它的數據發送任務后就能發送一個FIN來終止這個方向的連接。收到一個FIN只意味着
這一方向上沒有數據流動,一個TCP連接在收到一個FIN后仍能發送數據。首先進行關閉的一方將執行主動關閉,而另一方執行被動關閉。
TCP的連接的拆除需要發送四個包,因此稱為四次揮手(four-way handshake)。客戶端或服務器均可主動發起揮手動作,在socket編程中,任何一方執行close()操作即可產生揮手操作。
步驟如下:
第一步:當主機A的應用程序通知TCP數據已經發送完畢時,TCP向主機B發送一個帶有FIN附加標記的報文段(FIN表示英文finish)。
第二步:主機B收到這個FIN報文段之后,並不立即用FIN報文段回復主機A,而是先向主機A發送一個確認序號ACK,同時通知自己相應的應用程序:對方要求關閉連接(先
發送ACK的目的是為了防止在這段時間內,對方重傳FIN報文段)。
第三步:主機B的應用程序告訴TCP:我要徹底的關閉連接,TCP向主機A送一個FIN報文段。
第四步:主機A收到這個FIN報文段后,向主機B發送一個ACK表示連接徹底釋放。
在網絡編程時,常常會創建套接字,套接字使用完成后常常關閉套接字,那么關閉Socket時客戶端和服務端究竟做了什么?
關閉socket分為主動關閉(Active closure)和被動關閉(Passive closure)兩種情況。
主動關閉是指有本地主機主動發起的關閉;而被動關閉則是指本地主機檢測到遠程主機發起關閉之后,作出回應,從而關閉整個連接。
被動關閉的情況下:
客戶端發起中斷連接請求,也就是發送FIN報文。
服務器接到FIN報文后,報文意思是說“我客戶端沒有數據要發給你了,但是如果你還有數據沒有發送完成,則不必急着關閉Socket,可以繼續發送數據”。
所以服務器先發送ACK,告訴客戶端:“你的請求我收到了,但是我還沒准備好,請繼續你等我的消息"。
這個時候客戶端就進入FIN_WAIT狀態,繼續等待服務器的FIN報文。
當服務器確定數據已發送完成,則向客戶端發送FIN報文,告訴客戶端:“好了,我這邊數據發完了,准備好關閉連接了"。
Client端收到FIN報文后,"就知道可以關閉連接了,但是他還是不相信網絡,怕服務器不知道要關閉,所以發送ACK后進入TIME_WAIT狀態,如果服務器沒有收
到ACK則可以重傳“。
Server端收到ACK后,"就知道可以斷開連接了"。
Client端等待了2MSL后依然沒有收到回復,則證明Server端已正常關閉,那好,我Client端也可以關閉連接了。就這樣,TCP連接就這樣關閉了!
MSL意思是最大段生命周期(Maximum Segment Lifetime)表明一個包存在於網絡上到被丟棄之間的時間。每個IP包有一個TTL(time_to_live),當它減到0時則包被丟棄。
每個路由器使TTL減一並且傳送該包。當一個程序進入TIME_WAIT狀態時,他有2個MSL的時間,這個充許TCP重發最后的ACK,萬一最后的ACK丟失了,使得FIN被重新傳輸。
在2MSL等待狀態完成后,socket進入CLOSED狀態。
整個過程客戶端所經歷的狀態如下:
而服務器所經歷的過程如下:
注意: 在TIME_WAIT狀態中,如果TCP client端最后一次發送的ACK丟失了,它將重新發送。TIME_WAIT狀態中所需要的時間是依賴於實現方法的。典型的值為30秒、1分鍾和2分鍾。等待之后連接正式關閉,並且所有的資源(包括端口號)都被釋放。
問題1:為什么連接的時候是三次握手,關閉的時候卻是四次握手?
因為當Server端收到Client端的SYN連接請求報文后,可以直接發送SYN+ACK報文。其中ACK報文是用來應答的,SYN報文是用來同 步的。但是關閉連接時,當Server端
收到FIN報文時,很可能並不會立即關閉SOCKET,所以只能先回復一個ACK報文,告訴Client端,"你 發的FIN報文我收到了"。只有等到我Server端所有的報文都發送完了,我
才能發送FIN報文,因此不能一起發送。故需要四步握手。
問題2:為什么TIME_WAIT狀態需要經過2MSL(最大報文段生存時間)才能返回到CLOSE狀態?
雖然按道理,四個報文都發送完畢,我們可以直接進入CLOSE狀態了,但是我們必須假象網絡是不可靠的,有可以最后一個ACK丟失。所以TIME_WAIT狀態就是用來重發
可能丟失的ACK報文。
三、winsocks2關閉套接字的函數有:closesocket,shutdown,WSASendDisconnect.。
int closesocket( SOCKET s)的作用是關閉指定的socket,並且回收其所有的資源。
int shutdown( SOCKET s, int how)則是用於任何類型的套接口禁止接收、禁止發送或禁止收發,但並不對資源進行回收。
how參數為0時,則該套接口上的后續接收操作將被禁止。這對於低層協議無影響。
how為1時,則禁止后續發送操作。對於TCP,將發送FIN。
how為2時,則同時禁止收和發。