1. 程式人生 > >為什麼TCP建立連線協議是三次握手,而關閉連線卻是四次握手呢?

為什麼TCP建立連線協議是三次握手,而關閉連線卻是四次握手呢?

看到了一道面試題:“為什麼TCP建立連線協議是三次握手,而關閉連線卻是四次握手呢?為什麼不能用兩次握手進行連線?”,想想最近也到金三銀四了,所以就查閱了相關資料,整理出來了這篇文章,希望對你們有所幫助。

TCP 連線

我們先來補一下基礎什麼是 TCP 協議?傳輸控制協議( Transmission Control Protocol, TCP )是種面向連線、確保資料在端到端間可靠傳輸的協議。面向連線是插在傳送資料前,需要先建立一條虛擬的鏈路,然後讓資料在這條鏈路上“流動”完成傳輸。

TCP 是可靠的,會盡自己最大的努力去完成資料傳輸,TCP 協議比較複雜,可以看下面這張 TCP 協議的報文頭圖片:

內容非常的豐富,跟我們今天要討論的連線協議相關的就是中間那六個狀態位: URG、ACK、PSH、RST、SYN、FIN ,都置為 1 表示有效,在這六個當中,我們主要關注重點關注 ACK、SYN、FIN 這三個。下面解釋一下這三個狀態位:

ACK:用於對收到的資料進行確認,所確認的資料由確認序列號表示。

SYN:用作建立連線時的同步訊號

FIN:表示後面沒有資料需要傳送,通常意昧著所建立的連線需要關閉了。

好了,到這裡,TCP 的基礎知識我們就知道了,下面我們就來看看為什麼
是三次握手,而不是四次或者兩次,為了讓你更好的理解,我把知乎上一個高贊特別形象的比喻放在這裡,希望對你有所幫助。

兩次和四次都會出現問題,三次就剛剛好,希望這張圖能夠讓你更好的理解為什麼是三次握手。

我們已經知道了 TCP 協議是三次握手,為什麼是三次握手呢?我們先來看看下面這張 TCP 協議建立連線的時序圖。

總體來說就是呼叫、應答、迴應,我們來詳細的介紹每一步:

  • 第一步: A 機器向 B機器發出一個數據包並將 SYN 設定為 1 ,表示希望建立連線。這個包中的序列號假設是 X。
  • 第二步: B 機器收到 A機器發過來的資料包後,通過 SYN 得知這是一個建立連線的請求,於是傳送一個響應包並將 SYN 、ACK 標記都置為 1。假設這個包中的序列號是 y ,而確認序列號必須是 x+l ,表示收到了 發過來的 SYN,TCP 中, SYN 被當作資料部分的一個位元組。
  • 第三步: A 收到 的響應包後需進行確認,確認包中將 ACK ,並將確認序列號設定為 y+ ,表示收到了來自B 的 SYN

經過這三步之後,兩臺伺服器就建立連線了,可以進行通訊資料傳輸了。為什麼要三次握手呢?主要是為了資訊對等和防止出現請求超時導致髒連線。

第一是為了保證兩臺機器資訊對等,確保兩臺機器都沒有什麼問題:

只有三次握手之後才能夠保證兩臺伺服器都完全沒有問題,各自具備發報和收報能力。

第二是防止出現請求超時導致髒連線,看下面這張圖:

為什麼會出現髒連線?因為TTL 網路報文的生存時間往往都會超 TCP 請求超時時間,如果兩次握手就可以建立連線 ,傳輸資料並釋放連線後,第一個超時的連線請求才到達 B 機器的話,B 機器會以為是 A 建立新連線的請求,然後確認同意建立連線。因為 A 機器的狀態不是 SYl_SENT ,所以直接丟棄了 B 的確認資料 ,以致最後只是 B 機器單方面建立連線完畢。

三次握手就可以解決這個問題,因為需要 A 伺服器確認了才真正的建立了連線。

TCP 四次揮手

上面介紹了 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 協議相關文章,如有雷同,請多多包涵了。原創不易,碼字不易,還希望大家多多支援。若文中有所錯誤之處,還望提出,謝謝。

歡迎掃碼關注微信公眾號:「平頭哥的技術博文」,和平頭哥一起學習,一起進步。

相關推薦

為什麼TCP建立連線協議握手關閉連線握手

看到了一道面試題:“為什麼TCP建立連線協議是三次握手,而關閉連線卻是四次握手呢?為什麼不能用兩次握手進行連線?”,想想最近也到金三銀四了,所以就查閱了相關資料,整理出來了這篇文章,希望對你們有所幫助。 TCP 連線 我們先來補一下基礎什麼是 TCP 協議?傳輸控制協議( Transmission Contr

TCP基礎 —— 為什麼建立連線需要握手斷開連線則需要?能不能是

一、TCP包概述 一個 segment 包含 header 和 data 兩個部分,對於這篇文章需要理解的就是,Sequence

socket的連線握手)和關閉過程(握手)與伺服器各種關閉對客戶端的不同影響

之前對socket的TIME_WAIT看的很迷糊,今天在這裡總結下,以備今後檢視: socket的連線(三次握手)和關閉過程(四次握手): socket狀態變遷圖: 伺服器和客戶端各種狀態總結: CLOSED:沒有使用該套接字 LISTEND:套接字正在監聽連線 SYN

TCP連線建立只需要握手為什麼斷開連線需要揮手?

通常TCP連線是由客戶端向伺服器發起和斷開的。因為只有伺服器在監聽埠,客戶端上沒有監聽埠,所以客戶端無法接收主動來的連線。而客戶端獲得了自己想要的資源或者服務之後,就會斷開連線。下面的三次握手和四次揮手描述了典型情況。 TCP連線建立過程: 1、客戶端向伺服器傳送SYN,其中seq=x。 2、伺服器

TCP/IP連線為什麼要握手不是兩

 拿京城和縣衙比作需要進行三次握手的兩端,他們之間的運輸貨物比作TCP/IP之間的通訊,下面是京城端的自述: 這三次握手主要是為了驗證我這邊和縣衙那邊的發信/收信能力沒問題, 這樣就證明連線是通的, 可以正式發貨了。” 第一次握手:京城發信,縣衙收到了,此時縣衙就

【轉】TCP建立連接握手和釋放連接握手

eight 請求 置1 計時器 響應 發送數據 出現 期望 本地 在談及TCP建立連接和釋放連接過程,先來簡單認識一下TCP報文段首部格式的的幾個名詞(這裏只是簡單說明,具體請查看相關教程) 序列號seq:占4個字節,用來標記數據段的順序,TCP把連接中發送的所有數

TCP為什麼要有握手不是

  其實這個問題就是說,為什麼tcp不能兩次握手,或者一次握手就建立連線,和三次握手時怎麼解決兩次握手中的問題的。     為什麼不能一次握手很容易理解,TCP是面向連線的,一次握手肯定建立不了連線,一條資訊發出去連個回信都沒有怎麼連線?所以問題在為什麼不能兩次握手,這

tcp為什麼要握手不能二握手

http://bbs.csdn.net/topics/390706512?page=1 謝希仁版《計算機網路》中的例子是這樣的,“已失效的連線請求報文段”的產生在這樣一種情況下:client發出的第一個連線請求報文段並沒有丟失,而是在某個網路結點長時間的滯留了,以致延誤到連

TCP為什麼是握手不是兩

1. TCP的三次握手最主要是防止已過期的連線再次傳到被連線的主機。 如果採用兩次的話,會出現下面這種情況。 比如是A機要連到B機,結果傳送的連線資訊由於某種原因沒有到達B機; 於是,A機又發了一次,結果這次B收到了,於是就發信息回來,兩機就連線。 傳完東西后,斷開。 結果

基於UDP/TCP的常見協議的埠號功能及作用大全

轉載自:http://blog.51cto.com/13445059/2061325 TCP 協議名稱 埠號 套接字 作用 Telnet 專司終端模擬 23 T

多執行緒問題個執行緒輪流進行每個執行緒進行n操作共執行n*n*3操作。本程式碼用三軍攻擊做演示通俗易懂。

package com.yyj.zxy; public class SanJunFight { /** * 三隻部隊輪流上戰場,每隻部隊在戰場上每一輪只能進行n次攻擊; * 合計攻擊300次則停止攻擊; */ private static int coun

實驗計算分段函數 第計算分段函數和循環NEW 第五分支+循環加強版 實驗報告

scan amp 函數 寬度 中大 解決方法 sca -1 三次 一.實驗題目,設計思路,實現方法 第四次分支+循環 加強版 (2-2計算個人所得稅,2-7 裝睡,2-8計算天數) 設計思路:2-2 用if-else的語句,與計算分段函數的題類似的做法;2-7 運用for語

什麼是微信二開發如何進行微信二開發?

近年來,隨著微信業務的突飛猛進,微信可謂是開創了中國即時通訊業的又一先河。想必大家都聽說過微信二次開發,那麼什麼是微信二次開發呢?如何進行微信二次開發呢?下面就由藝形藝意工作室創始人黎想將從3W角度為大家詳細介紹什麼是微信二次開發,如何進行微信二次開發。那麼也請大家帶著這個問題和我一起看

一個數組中除了有兩個數字只出現一其他數字都出現兩求出這兩個出現一的數字

求出兩個只出現一次的數字 首先,我們知道兩個相同的數字進行異或操作時為0,如果題目裡面只有一個數字出現一次的話,我們就可以直接對陣列中的所有數字進行異或操作,最後得到的數字就是單獨出現的那個數字,但

【演算法】給定一個數組除了一個數出現1之外其餘數都出現3輸出出現一的那個數。

給定一個數組,除了一個數出現1次之外,其餘數都出現3次。找出出現一次的數。如:{1, 2, 1, 2, 1, 2, 7},找出7.格式:第一行輸入一個數n,代表陣列的長度,接下來一行輸入陣列A[n],(輸入的陣列必須滿足問題描述的要求),最後輸出只出現一次的數。

SQL語句中為什麼where子句不能使用列別名order by可以?

當select的表示式很長時,我們經常會用as子句為該表示式指定別名,然而卻發現無法在Where條件中直接使用該別名作為判斷條件.  例如下面的SQL語句:  select id, (c1 + c2) as s from t1 where s > 100  執行會

谷歌瀏覽器和internet explorer所有網頁打不開Edge瀏覽器可以開啟網頁

我由於安裝Visualbox進行hadoop分散式環境搭建導致了題目中的問題,經過網上查閱資料,才知道原來是LSP異常所致。只需要在命令列視窗中輸入下面命令: netsh winsock reset

【Zero'Coffee】咖啡總有點苦澀,而苦澀之中韻育著甜美!人生就象一杯咖啡在苦澀的途中亦有無限的甜蜜等待著去品嚐;人生的意義不在於會得到什麼,而在於人生旅途中將體驗到什麼!好好享受人生吧從零度開始從Java開始!試著品嚐咖啡品嚐人生!

咖啡總有點苦澀,而苦澀之中卻韻育著甜美!人生就象一杯咖啡,在苦澀的途中亦有無限的甜蜜等待著去品嚐;人生的意義不在於會得到什麼,而在於人生旅途中將體驗到什麼!好好享受人生吧,從零度開始,從Java開始!...

【C】為什麼靜態變數會被初始化為0自動變數不會被初始化?

把自動變數初始化為0的代價,將會增加函式呼叫的代價。C語言非常注重執行速度。 然而,把全域性變數區初始化為0,僅僅在程式啟動時候產生成本。這也許是這個問題的主要原因。 更精確的說,C++並不把靜態變數初始化為0,他們有自己的預設值,對於原生型別(native types)來

對於c/c++中char型可以輸入整型int型不能輸入字元

問題根源在於:你可能認為字母和一些符號才算字元。其實,翻開字元ascii表,你可以看到數字字元也是字元,製表符、換行符、分頁符、空字元之類的也列在其中,也就是說,'a'是字元,'1'同樣是字元,所以輸