天天看點

netty tcp服務端主動斷開用戶端_一篇搞懂TCP的三次握手四次揮手三次握手四次揮手總結後續

netty tcp服務端主動斷開用戶端_一篇搞懂TCP的三次握手四次揮手三次握手四次揮手總結後續

TCP的三次握手四次揮手,估計大家都聽過。但是真的能把每一步說明白的人比較少。我還記得在之前面試的時候被面試官一頓問,然後一臉懵B... 都是大學沒好好上課?,這篇文章就跟大家講講到底這三握四揮是在搞什麼飛機。

三次握手

握手是指的雙方進行連接配接的操作。

netty tcp服務端主動斷開用戶端_一篇搞懂TCP的三次握手四次揮手三次握手四次揮手總結後續

三次握手(圖檔來自網絡)

為什麼是三次握手

确認通信能力

我們要明白,如果需要進行通信,首先需要保證的是雙方都具有發信和收信能力。在不知雙方能力狀态下進行的通信都是無法保證可靠性和通信效率的。那麼通信雙方如何确認對方的通信能力呢?

  1. A請求B進行連接配接。(B已确認B的收信能力和A的發信能力)
  2. B傳回ACK相應。(A已确認雙方的收發能力)
  3. A傳回ACK并建立連接配接。(B确認雙方收發能力) 上面可以看到,至少是進行三次握手,才能确認雙方能力。

防止産生髒資料連接配接

網絡通信情況複雜,不可能保證每一消息都能正常到達其目的地。在TCP連接配接中,TTL的網絡封包的生存時間一般都會比TCP的連接配接逾時時間要長。這樣就有可能出現一個問題。A在發送第一次連接配接請求時,可能網絡擁塞,導緻資料包未短時間内到達。到達逾時時間後,A又發送了一次連接配接請求,這次正常進行連接配接。連接配接結束斷開後,A的第一次連接配接請求到達B,B傳回ack。如果是兩次握手,A通過目前的狀态,直接拒絕B的請求,但B會單方面認為連接配接已經建立,實際上并不是...

每一次握手到底是傳輸了什麼?

想知道除了ip和端口号,每次傳輸的資訊是什麼,我們首先得知道TCP傳輸資訊的結構。

netty tcp服務端主動斷開用戶端_一篇搞懂TCP的三次握手四次揮手三次握手四次揮手總結後續

TCP資料包結構(圖檔來自網絡)

第一次握手

  • 首先會将TCP的header部分的控制位(上圖的flags)中的SYN置為1。表示希望建立連接配接。
  • 還有一個重要的資料,seq,即序号。這個東西是幹嘛用的呢?這個涉及到TCP安全性和可靠性,與ack即确認号緊密相關。TCP在傳輸資料時,如果資料比較大,會進行拆分操作,将大資料拆成一個個小的資料包。序号就是在這個時候用的。我們必須要知道這個包的順序是什麼,才能把真正的資料在服務端還原。seq的順序并不是從0或者1開始的,而是一個随機值。因為如果序号從1開始,那麼整個通信的過程非常容易被預測。正因為是随機的,是以對方不知道你的seq,是以我們需要在開始收發資料之前,将seq先發送給對方。序号的初始值的傳遞就是通過SYN=1的操作傳遞的。

用戶端此時處于同步狀态,即可以建立連接配接。服務端處于監聽狀态。

第二次握手

  • 标志位。因為已經收到了用戶端的建立連接配接請求。是以必須要發送ack,以告知用戶端自己已經收到消息。是以ACK的标志位要置為1,且SYN也是1,因為還未建立連接配接。
  • seq。同第一次握手一樣,也是一個随機值(TCP為全雙工,是以雙方都需要保留seq友善處理資料包)。
  • ack。是對用戶端發過來的序列号進行計算得到的。

服務端處于SYN接收狀态。

第三次握手

  • 标志位。此時隻需要ACK=1。SYN已經不需要了,雙方已經同步完seq等資訊。
  • seq。可以說是第二次握手收到的ack。
  • ack。是對第二次握手收到的序列号進行計算得到的。用以告知已收到二次握手資訊。

用戶端處于連接配接建立狀态,服務端收到資訊之後也會進入連接配接建立狀态,雙方可以進行通信。

四次揮手

TCP連接配接在資料傳輸完成之後需要關閉,不然會一直占用系統資源。TCP的連接配接關閉需要四次通信才行,分手也是個麻煩事兒。

為什麼四次才能斷開連接配接呢?

分手這件事情,兩邊都說明白,分别斷開即可。但是想要确認對方都要斷開,那麼一次兩次是不夠的。

netty tcp服務端主動斷開用戶端_一篇搞懂TCP的三次握手四次揮手三次握手四次揮手總結後續

四次揮手(圖檔來自網絡)

我們還是拿A、B來舉例。假設A要主動斷開和B的連接配接。

  1. A發送斷開請求。(需要等待B的回複,不然B未收到消息 就單方面的斷開有點不負責任。逾時重傳)
  2. B收到請求并回複A。(B收到請求後,很傷心,但是沒有辦法,隻能斷開連接配接,但是B是被動的接收斷開,是以需要通知其應用程式做關閉準備)
  3. B這邊準備完了,通知A可以斷開了。
  4. A回複B,我收到消息了,斷開連接配接吧。

請求發送的資訊是什麼?

下面是抓包看到的資料

netty tcp服務端主動斷開用戶端_一篇搞懂TCP的三次握手四次揮手三次握手四次揮手總結後續

關閉由哪方開始?

答案是哪邊都可以,無論是用戶端還是伺服器端,都可以主動發起關閉請求。發起關閉請求的前提是資料發送完畢,不一定非得等待對方确認完成。

第一次揮手

假設用戶端發起關閉請求。那麼用戶端發完消息後,會進入FIN_WAIT階段。此處已經無法再發送應用程式消息,隻能處理關閉相關資訊。

第二次揮手

服務端收到第一次揮手消息後,傳回收到消息的ack。服務端會進入CLOSE_WAIT階段。這個階段是等待關閉階段,通知應用程式發送剩餘資料,處理現場資訊,關閉相應資源。

第三次揮手

你應該有點好奇為什麼第三次揮手和第二次揮手都是同一個服務。第二次主要是一個ack響應,第三次主要是一個服務端關閉通知消息。兩者目的不同。等到三次揮手完畢,那麼服務端會進入LAST_ACK狀态,即等待最後用戶端(主動發起關閉的一方)的ack确認。

第四次揮手

第四次揮手是主動發起關閉的一方A,對被動關閉一方B的FIN消息的确認。第四次資訊發送完成後,A會進入TIME_WAIT階段,而不是直接删除套接字。具體原因我們在下面講。收到第四次揮手資訊後,B會直接進行關閉操作。

為什麼會有TIME_WAIT?

還是那句話,網絡并不是一個理想世界,任何異常情況都有可能發生。為了保證TCP連接配接能夠正常關閉,主動發起關閉方不能直接删除套接字,而是需要經過一段時間等待。這個時間一般是2MSL(Maxumun Segment Lifetime 最大封包生存時間)。原因如下

  • 确認被動關閉方能夠正常進入關閉狀态。假設B未收到A最後的一個ack,會再次發送FIN消息(第三次揮手),如果A已經CLOSE了,那麼B就會一直重試發送。是以A必須要進行一段時間的等待。
  • 防止失效請求。假設A關閉了此次連接配接,又重新在原來的端口号上開啟了新的連接配接。原來在網絡上發送的一些包(已失效但未超過ttl)到來之後,無法進行區分是否是正常的包,導緻資料混亂。

舉個例子來證明沒有TIME_WAIT的情況。

  1. A斷開了,并且删除了套接字。
  2. B沒有收到A的最後一次ack,導緻FIN重發。
  3. A重新開啟了新的套接字新的連接配接,但是這個套接字和之前删除的套接字擁有相同的端口号。
  4. B後來重發的FIN會錯誤的跑到新的套接字,導緻A開始執行斷開操作。

是以TIME_WAIT也是為了防止上面的誤删除。

總結

在并發量很高的時候,熟悉TCP的原理和參數調優變得尤為重要。我們關注的不僅僅是幾次握手、幾次揮手,也應該關注一些細節,細節決定成敗。更應該多問問為什麼如此設計,能解決什麼問題。

後續

後續主要是與大家分享讨論一下對TCP的滑動視窗機制和可靠性保障的了解。如果有時間,可以跟大家分享一下TCP的參數等配置相關内容。

覺得有收獲就關注一下吧~

netty tcp服務端主動斷開用戶端_一篇搞懂TCP的三次握手四次揮手三次握手四次揮手總結後續
netty tcp服務端主動斷開用戶端_一篇搞懂TCP的三次握手四次揮手三次握手四次揮手總結後續

繼續閱讀