傳輸層(一)TCP的三次握手和四次揮手及關閉套接字的原理


TCP連接需三次握手才能建立,斷開連接則需要四次握手。

   客戶端TCP狀態遷移:
  CLOSED->SYN_SENT->ESTABLISHED->FIN_WAIT_1->FIN_WAIT_2->TIME_WAIT->CLOSED
   服務器TCP狀態遷移:
  CLOSED->LISTEN->SYN收到->ESTABLISHED->CLOSE_WAIT->LAST_ACK->CLOSED
  整個過程如下圖所示:
   一、建立TCP連接
   三次握手:所謂的“三次握手”即對每次發送的數據量是怎樣跟蹤進行協商使數據段的發送和接收同步,根據所接收到的數據量而確定的數據確認數及數據發送、接收完畢后何時撤消聯系,並建立虛連接。
   為了提供可靠的傳送,TCP在發送新的數據之前,以特定的順序將數據包的序號,並需要這些包傳送給目標機之后的確認消息。TCP總是用來發送大批量的數據。當應用程序在收到數據后要做出確認時也要用到TCP。
  位碼即 TCP標志位,有6種標示: SYN(synchronous 建立聯機)、 ACK(acknowledgement 確認)、 PSH(push 傳送) 、 FIN(finish 結束)、 RST(reset 重置)、URG(urgent 緊急)
   確認號:其數值等於發送方的發送序號 +1(即接收方期望接收的下一個序列號)。
  詳細過程如下:
   第一次:
  第一次握手:建立連接時,客戶端發送SYN包(SYN=j)到服務器,並進入SYN_SENT狀態,等待服務器確認;SYN:同步序列編號( Synchronize Sequence Numbers)。
   第二次:
  第二次握手:服務器收到SYN包,必須確認客戶的SYN(ACK=j+1),同時自己也發送一個SYN包(syn=k),即SYN+ACK包,此時服務器進入SYN_RECV狀態。
   第三次:
  第三次握手:客戶端收到服務器的SYN+ACK包,向服務器發送確認包ACK(ack=k+1),此包發送完畢,客戶端和服務器進入ESTABLISHED(TCP連接成功)狀態,完成三次握手。
  三次握手的流程圖如下:
   在三次握手過程中,還有一些重要概念:
   未連接隊列:

   在三次握手協議中,服務器維護一個未連接隊列,該隊列為每個客戶端的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時,則同時禁止收和發。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM