【俗話說】換個角度理解TCP的三次握手和四次揮手

PS:通俗一點的解釋都會在引用塊中安全

Nothing is true, Everything is permitted.服務器

0. 什麼是TCP

TCP,全稱Transmission Control Protocol,是一種面向鏈接、可靠的、基於字節流的單播協議。與咱們常說的TCP/IP協議不一樣,TCP/IP是一個協議族,涉及到OSI模型中的網絡層、應用層和應用層。而咱們要聊的TCP就是在傳輸層的協議,如今應用的特別普遍的HTTP請求,就是基於TCP的。微信

1. 三次握手

所謂面向鏈接很好理解,就像咱們要對遠程服務器發出一個指令,首先咱們須要登陸上去。這個登陸就是一個鏈接的過程。網絡

在作數據交換以前,通訊雙方必須在彼此創建一條鏈接。也就是通訊雙方都維護了一份對方的信息,好比IP地址和端口號。說到創建鏈接,就不得不提到經典的三次握手和四次揮手。app

1.1 爲何不兩次握手

三次握手讓通訊雙方都明確有一個鏈接正在創建,也爲了確保客戶端和服務器同時具備發送接收的能力。而兩次握手作不到這一點。咱們如今從另一個角度來看一下三次握手,那就是爲何要三次握手?我兩次握手它不香嗎?讓咱們用一段對話來模擬若是真的採用兩次握手,會帶來什麼問題。tcp

朋友:喂,喂?聽獲得嗎spa

你:聽獲得…你聲音能不能小點code

這就是兩次握手。orm

按照人的邏輯來講,這已是一次正常的對話了是吧,下一步難道不是創建鏈接嗎?說下一步以前,須要先了解作三次握手的目的是什麼。三次握手讓通訊雙方都明確有一個鏈接正在創建,也爲了確保客戶端和服務器同時具備發送接收的能力。blog

咱們來分析一下上面的那段對話。

朋友問你能不能聽到,說明朋友具備發送能力;你聽到了朋友的問題,說明你具備接收能力

若是隻有兩次握手,問題在哪兒呢?

站在朋友的角度,他知道你同時具備發送接收能力

但站在你(服務器)的角度,你只知道朋友具備發送能力,由於你不知道你發的聲音能不能小點,他到底有沒有收到

服務器不清楚客戶端是否有接收能力的狀況下,就算數據包真的發出去了,但沒法知道客戶端是否收到了數據。這樣的就是不可靠的鏈接了。

並且,真實的網絡傳輸中,出現網絡延遲是常有的事,若是客戶端發送了請求創建鏈接的數據包,因爲網絡延遲,數據包沒有到達,客戶端又發了一次,服務器收到以後創建了鏈接。

可是當前的鏈接關閉後,因爲網絡延遲的沒有到達的包到了服務器,服務器又創建了鏈接,可是此時客戶端已經斷開了,這樣就白白浪費了服務器的資源。

若是以爲上面的例子仍是不能讓你理解, 爲何兩次握手不行。請看下面這個終極例子。

朋友:快借我點錢,XX寶帳號123XXXXXXXX

你:好的, 你的賬號是123XXXXXXXX嗎

。。。。。。(無應答)

你的心裏:??????

若是你是被借錢的那個,你敢把錢轉過去嗎?

0341fda0555dc92b70a2ea4874115d5b
0341fda0555dc92b70a2ea4874115d5b

簡單總結一下兩次握手所帶來的問題:不可靠,還會形成網絡資源的浪費。

1.2 三次握手的過程

上面咱們討論了爲何要三次握手,接下來咱們用幾個專業術語來解釋一下三次握手的過程。

  • 服務器開始監聽某個端口,此時服務器進入了LISTEN狀態

  • 客戶端最初是CLOSED狀態,而後向服務器發送一個SYN標誌位的數據包,主動發起鏈接。客戶端變成SYN-SENT狀態

  • 服務器接收到客戶端的SYN數據包,經過標誌位知道了客戶端想要創建鏈接。因而回了客戶端一個SYN和ACK,表示收到了請求。服務器的自身狀態變爲了SYN-RCVD

  • 客戶端收到了服務器的ACK,表示服務器知道了客戶端想要創建鏈接。而後客戶端再給服務器回了一個ACK表示本身收到了(或者說可以收到)服務器的消息,發送完這個ACK後,客戶端的狀態變成了ESTABLISH

  • 服務器收到了客戶端的ACK,服務器的狀態也變成ESTABLISH

2. 四次揮手

2.1 模擬四次揮手

老規矩,仍是讓咱們用一段對話來模擬TCP的四次揮手。

場景,你跟你的朋友們正在外面high

你:大家繼續玩,我就先走了,明天還要上班(第一次)

老鐵:(老鐵看到你在跟他說話且從你說的話中知道你要走了,老鐵也用肢體語言告訴你他知道你要走了)(第二次)

老鐵:那好吧, 路上注意安全哈 (第三次)

你:好的,下次再約 (第四次)

這就是通俗版本的四次揮手的解釋,下面從專業的角度來看看。

2.2 四次揮手的過程

咱們來看一下完整的流程。

  • 最初,客戶端和服務器都處於ESTABLISH狀態

  • 客戶端想要斷開鏈接,便主動向服務器發送標誌位爲FIN的數據包。發送以後客戶端的狀態變爲FIN-WAIT-1,同時客戶端也變成了半關閉狀態,即沒法向服務器發送數據包了,只能接收來自服務器的數據

  • 服務器收到客戶端的FIN數據包,狀態變爲CLOSE-WAIT,並回給客戶端一個表示確認的數據包ACK

  • 客戶端收到了ACK以後,狀態變爲FIN-WAIT-2

  • 而後,服務器向客戶端發送FIN數據包,服務器狀態變爲LAST-ACK

  • 客戶端收到FIN數據包,客戶端狀態變爲TIME-WAIT。而後回一個確認數據包ACK給服務器

  • 而後客戶端等待2MSL,若是在這段時間內,沒有收到服務器重發的消息,說明服務器收到了ACK

  • 四次揮手到此結束,鏈接斷開

咱們再來模擬一次剛剛的場景。

場景,你跟你的朋友們正在外面high

你:大家繼續玩,我就先走了,明天還要上班(第一次)

老鐵:(老鐵喝high了,反射弧無限延長)

你確定得再說一次啊,給朋友說你要走了,因而你又說了一次。

你:大家繼續玩,我就先走了,明天還要上班(第一次)

老鐵:(老鐵喝high了,反射弧無限延長)

。。。。。。

如此反覆

實際狀況是,若是是兩次揮手,也就是把服務器給客戶端的ACK和FIN合併爲同一個,若是此時網絡出現了延遲,站在客戶端的角度來看,客戶端會認爲剛剛發送的FIN報文並無到達服務器,因而會在再從新發送一次。若是延遲的時間較長,那麼客戶端將會一直從新發送FIN的TCP報文。

2.3 對比分析

結合抽象和具體的四次揮手,其實就很好理解了,咱們用一個表格來總結一下。

描述狀態 實際狀況
你和你的朋友在外面high 客戶端和服務器創建了鏈接
你和朋友說你要走了 客戶端主動向服務器發送FIN,客戶端狀態變爲FIN-WAIT-1
你的朋友聽到了並理解了你要說的話,並經過肢體語言反饋給你他知道了 服務器收到FIN數據包,並回了一個ACK,服務器的狀態變爲CLOSE-WAIT。客戶端收到ACK以後變爲FIN-WAIT-2
你的朋友說「那好吧, 路上注意安全哈」 服務器向客戶端發送FIN包,服務器變爲LAST-CHECK。
你說「好的,下次再約」 客戶端收到FIN包後狀態變爲TIME-WAIT。並回一個ACK給服務器。
你遲疑了一下,你的朋友並無挽留你 客戶端等待2MSL,若是沒有收到服務器的重發消息,則說明服務器收到了ACK。
你離開了和朋友的聚會 四次揮手結束,鏈接斷開

2.4 爲何要等待

MSL,即Maximun Segment LifeTime,報文最大生存時間。爲何在TIME-WAIT以後還須要等待2MSL呢?主要是兩個緣由,讓咱們結合例子來理解一下。

保證服務器收到ACK

假設你說了「好的,下次再約」。因爲你們都在high,聲音太大了。致使你的朋友沒有聽到你說的「好的,下次再約」這句話,而後你轉頭就走了。

若是你站在你朋友的角度,確定會內心很不爽,好心提醒你,連句作別的話都沒有?

這種狀況就是服務器並無收到客戶端收到的ACK,站在服務器的角度,服務器並不知道客戶端收到了本身發的FIN包。也就不會斷開鏈接,可是客戶端已經單方面的斷開鏈接了。又形成了服務器的資源浪費,服務器也沒法進入正常的關閉鏈接狀態。

防止失效的數據包

一樣,你說了」好的, 下次再約「後,你沒有確認你的朋友是否聽到了,扭頭就走。你的朋友也喝多了,此時內心很不爽,罵了一句傻X。

這句話恰好被路過、站到了你剛剛站的位置上的哥們接住了,覺得在說他,內心就很不爽,提着拳頭就把你的朋友揍了一頓。

這種狀況是指,客戶端沒有等待2MSL就直接斷開,可是服務器此時仍然有些數據包須要發送,或者已經發了出去。可是數據包到了後,此時的端口已經被新的鏈接佔用了,老的TCP報文就會與新鏈接的TCP報文衝突、混淆。

3. 結尾

後面若是我有時間,會繼續嘗試把枯燥的理論抽象成生活中一些簡單的現象而且與專業的知識結合起來的文章風格,來幫助那些看理論知識很吃力的人。其實只要理解了整個思路,是不須要去死記硬背的。

若是文章中有不對的地方,還望各位大佬不吝賜教。

若是你以爲這篇文章對你有幫助,還麻煩點個贊關個注分個享留個言

也能夠微信搜索公衆號【SH的全棧筆記】,固然也能夠直接掃描二維碼關注

拜了個拜

相關文章
相關標籤/搜索