看到了一道面試題:「爲何TCP創建鏈接協議是三次握手,而關閉鏈接倒是四次握手呢?爲何不能用兩次握手進行鏈接?」,想一想最近也到金三銀四了,因此就查閱了相關資料,整理出來了這篇文章,但願對大家有所幫助。面試
咱們先來補一下基礎什麼是 TCP 協議?傳輸控制協議( Transmission Control Protocol, TCP )是種面向鏈接、確保數據在端到端間可靠傳輸的協議。面向鏈接是插在發送數據前,須要先創建一條虛擬的鏈路,而後讓數據在這條鏈路上「流動」完成傳輸。服務器
TCP 是可靠的,會盡本身最大的努力去完成數據傳輸,TCP 協議比較複雜,能夠看下面這張 TCP 協議的報文頭圖片:微信
內容很是的豐富,跟咱們今天要討論的鏈接協議相關的就是中間那六個狀態位: URG、ACK、PSH、RST、SYN、FIN ,都置爲 1 表示有效,在這六個當中,咱們主要關注重點關注 ACK、SYN、FIN 這三個。下面解釋一下這三個狀態位:網絡
ACK:用於對收到的數據進行確認,所確認的數據由確認序列號表示。tcp
SYN:用做創建鏈接時的同步信號學習
FIN:表示後面沒有數據須要發送,一般意昧着所創建的鏈接須要關閉了。3d
好了,到這裏,TCP 的基礎知識咱們就知道了,下面咱們就來看看爲何 是三次握手,而不是四次或者兩次,爲了讓你更好的理解,我把知乎上一個高贊特別形象的比喻放在這裏,但願對你有所幫助。cdn
兩次和四次都會出現問題,三次就剛恰好,但願這張圖可以讓你更好的理解爲何是三次握手。blog
咱們已經知道了 TCP 協議是三次握手,爲何是三次握手呢?咱們先來看看下面這張 TCP 協議創建鏈接的時序圖。圖片
整體來講就是呼叫、應答、迴應,咱們來詳細的介紹每一步:
通過這三步以後,兩臺服務器就創建鏈接了,能夠進行通訊數據傳輸了。爲何要三次握手呢?主要是爲了信息對等和防止出現請求超時致使髒鏈接。
第一是爲了保證兩臺機器信息對等,確保兩臺機器都沒有什麼問題:
只有三次握手以後纔可以保證兩臺服務器都徹底沒有問題,各自具有發報和收報能力。
第二是防止出現請求超時致使髒鏈接,看下面這張圖:
爲何會出現髒鏈接?由於TTL 網絡報文的生存時間每每都會超 TCP 請求超時時間,若是兩次握手就能夠建立鏈接 ,傳輸數據並釋放鏈接後,第一個超時的鏈接請求才到達 B 機器的話,B 機器會覺得是 A 建立新鏈接的請求,而後確認贊成建立鏈接。由於 A 機器的狀態不是 SYl_SENT ,因此直接丟棄了 B 的確認數據 ,以至最後只是 B 機器單方面建立鏈接完畢。
三次握手就能夠解決這個問題,由於須要 A 服務器確認了才真正的創建了鏈接。
上面介紹了 TCP 協議鏈接,有鏈接就有斷開,相對於三次鏈接,斷開卻須要四次揮手,怎麼理解呢?先看下面這個場景:
A:B 啊,我不想玩了。
B:哦,你不想玩了啊,我知道了。
這個時候,還只是 A 不想玩了,也即 A 不會再發送數據,可是 B 能不能在 ACK 的時候,直接關閉呢?固然不能夠了,頗有可能 A 是發完了最後的數據就準備不玩了,可是 B 還沒作完本身的事情,仍是能夠發送數據的,因此稱爲半關閉的狀態。
這個時候 A 能夠選擇再也不接收數據了,也能夠選擇最後再接收一段數據,等待 B 也主動關閉。
B:A 啊,好吧,我也不玩了,拜拜。
A:好的,拜拜。
這就是一個完整的關閉鏈接,在這個關閉的過程當中,一共說了四句話,咱們也稱之爲四次揮手。跟創建鏈接同樣,斷開時也是用狀態來表示,下面是斷開的時序圖:
咱們結合上面的時序圖和場景再來分析一下 TCP 斷開過程。
當 A 說「不玩了」,A 就進入 FIN_WAIT_1 的狀態,B 收到「A 不玩」的消息後,發送知道了,B 就進入 CLOSE_WAIT 的狀態。
A 收到「B 說知道了」,就進入 FIN_WAIT_2 的狀態,若是這個時候 B 直接跑路,則 A 將永遠在這個狀態。雖然 TCP 協議裏面並無對這個狀態的處理,可是 Linux 有,能夠調整 tcp_fin_timeout 這個參數,設置一個超時時間,最後 A 也會關閉的。
若是 B 沒有跑路,發送了「B 也不玩了」的請求到達 A 時,A 發送「知道 B 也不玩了」的 ACK 後,從 FIN_WAIT_2 狀態結束,按說 A 能夠跑路了,可是最後的這個 ACK 萬一 B 收不到呢?則 B 會從新發一個「B 不玩了」,這個時候 A 已經跑路了的話,B 就再也收不到 ACK 了,於是 TCP 協議要求 A 最後等待一段時間 TIME_WAIT,這個時間要足夠長,長到若是 B 沒收到 ACK 的話,「B 說不玩了」會重發的,A 會從新發一個 ACK 而且足夠時間到達 B。
要求 A 等待 TIME_WAIT還有一個緣由就是防止產生混亂,A 直接關閉了,可是這個時候 B是不知道的,可能在 A 關閉以前 B還發送了不少數據包,若是這時候 A 的端口被一個新的應用佔用了的話,那麼新的應用就會接收到上個鏈接中 B發送過來的數據包,這樣就混亂了,雖然這個數據包是無效的,可是等待 TIME_WAIT 能夠是一個雙保險,於是也須要等足夠長的時間,等到原來 B 發送的全部的包都死翹翹,再空出端口來。
以上就是 TCP 協議三次握手,四次揮手的緣由,但願這篇文章對您的學習或者工做有所幫助,若是您以爲文章不錯,還請您幫忙點個贊和轉發,謝謝。
目前互聯網上不少大佬都有 TCP 協議相關文章,若有雷同,請多多包涵了。原創不易,碼字不易,還但願你們多多支持。若文中有所錯誤之處,還望提出,謝謝。
歡迎掃碼關注微信公衆號:「平頭哥的技術博文」,和平頭哥一塊兒學習,一塊兒進步。