TCP 協議的三次握手與四次揮手過程詳解

序言

盡管TCP和UDP都使用相同的網絡層(IP),TCP卻向應用層提供與UDP完全不同的服務。TCP提供一種面向連接的、可靠的字節流服務。

面向連接意味著兩個使用TCP的應用(通常是一個客戶和一個服務器)在彼此交換數據之前必須先建立一個TCP連接。

本文將分別講解經典的TCP協議建立連接(所謂的“3次握手”)和斷開連接(所謂的“4次揮手”)的過程。

一 先認識 TCP 的報文格式

下面是 TCP 報文格式圖:


TCP報文格式.png
上圖中有幾個字段需要重點介紹下:
  • 序號 Seq序號,占32位,用來標識從TCP源端向目的端發送的字節流,發起方發送數據時對此進行標記。
  • 確認序號 Ack序號,占32位,只有ACK標志位為1時,確認序號字段才有效,Ack=Seq+1。
  • 標志位 共6個,即URG、ACK、PSH、RST、SYN、FIN等,具體含義如下:
(A)URG:緊急指針(urgent pointer)有效。
(B)ACK:確認序號有效。
(C)PSH:接收方應該盡快將這個報文交給應用層。
(D)RST:重置連接。
(E)SYN:發起一個新連接。
(F)FIN:釋放一個連接。

需要注意的是:
1.不要將確認序號Ack與標志位中的ACK搞混了。
2.確認方Ack=發起方Req+1,兩端配對。

二 3次握手過程詳解

所謂三次握手(Three-Way Handshake)即建立TCP連接,就是指建立一個TCP連接時,需要客戶端和服務端總共發送3個包以確認連接的建立。在socket編程中,這一過程由客戶端執行connect來觸發,整個流程如下圖所示:

三次握手.png

(1) 第一次握手

Client將標志位SYN置為1,隨機產生一個值seq=J,并將該數據包發送給Server,Client進入SYN_SENT狀態,等待Server確認。

(2) 第二次握手

Server收到數據包后由標志位SYN=1知道Client請求建立連接,Server將標志位SYN和ACK都置為1,ack=J+1,隨機產生一個值seq=K,并將該數據包發送給Client以確認連接請求,Server進入SYN_RCVD狀態。

(3) 第三次握手

Client收到確認后,檢查ack是否為J+1,ACK是否為1,如果正確則將標志位ACK置為1,ack=K+1,并將該數據包發送給Server,Server檢查ack是否為K+1,ACK是否為1,如果正確則連接建立成功,Client和Server進入ESTABLISHED狀態,完成三次握手,隨后Client與Server之間可以開始傳輸數據了。

SYN攻擊
在三次握手過程中,Server發送SYN-ACK之后,收到Client的ACK之前的TCP連接稱為半連接(half-open connect),此時Server處于SYN_RCVD狀態,當收到ACK后,Server轉入ESTABLISHED狀態。SYN攻擊就是Client在短時間內偽造大量不存在的IP地址,并向Server不斷地發送SYN包,Server回復確認包,并等待Client的確認,由于源地址是不存在的,因此,Server需要不斷重發直至超時,這些偽造的SYN包將產時間占用未連接隊列,導致正常的SYN請求因為隊列滿而被丟棄,從而引起網絡堵塞甚至系統癱瘓。SYN攻擊時一種典型的DDOS攻擊,檢測SYN攻擊的方式非常簡單,即當Server上有大量半連接狀態且源IP地址是隨機的,則可以斷定遭到SYN攻擊了,使用如下命令可以讓之現行:

#netstat -nap | grep SYN_RECV

三 4次揮手過程詳解

三次握手耳熟能詳,四次揮手估計就少有人知道了。所謂四次揮手(Four-Way Wavehand)即終止TCP連接,就是指斷開一個TCP連接時,需要客戶端和服務端總共發送4個包以確認連接的斷開。在socket編程中,這一過程由客戶端或服務端任一方執行close來觸發,整個流程如下圖所示:

四次揮手.png

由于TCP連接時全雙工的,因此,每個方向都必須要單獨進行關閉,這一原則是當一方完成數據發送任務后,發送一個FIN來終止這一方向的連接,收到一個FIN只是意味著這一方向上沒有數據流動了,即不會再收到數據了,但是在這個TCP連接上仍然能夠發送數據,直到這一方向也發送了FIN。首先進行關閉的一方將執行主動關閉,而另一方則執行被動關閉,上圖描述的即是如此。

第一次揮手:

Client發送一個FIN,用來關閉Client到Server的數據傳送,Client進入FIN_WAIT_1狀態。

第二次揮手:

Server收到FIN后,發送一個ACK給Client,確認序號為收到序號+1(與SYN相同,一個FIN占用一個序號),Server進入CLOSE_WAIT狀態。

第三次揮手:

Server發送一個FIN,用來關閉Server到Client的數據傳送,Server進入LAST_ACK狀態。

第四次揮手:

Client收到FIN后,Client進入TIME_WAIT狀態,接著發送一個ACK給Server,確認序號為收到序號+1,Server進入CLOSED狀態,完成四次揮手。

上面是一方主動關閉,另一方被動關閉的情況,實際中還會出現同時發起主動關閉的情況,具體流程如下圖:

四次握手.png

流程和狀態在上圖中已經很明了了,在此不再贅述,可以參考前面的四次揮手解析步驟。

補充

a. 默認情況下(不改變socket選項),當你調用close( or closesocket,以下說close不再重復)時,如果發送緩沖中還有數據,TCP會繼續把數據發送完。

b. 發送了FIN只是表示這端不能繼續發送數據(應用層不能再調用send發送),但是還可以接收數據。

c. 應用層如何知道對端關閉?通常,在最簡單的阻塞模型中,當你調用recv時,如果返回0,則表示對端關閉。在這個時候通常的做法就是也調用close,那么TCP層就發送FIN,繼續完成四次握手。如果你不調用close,那么對端就會處于FIN_WAIT_2狀態,而本端則會處于CLOSE_WAIT狀態。這個可以寫代碼試試。

d. 在很多時候,TCP連接的斷開都會由TCP層自動進行,例如你CTRL+C終止你的程序,TCP連接依然會正常關閉,你可以寫代碼試試。

常見面試題

(1) 三次握手是什么或者流程?四次握手呢?

答案:前面分析就是。

(2) 為什么建立連接是三次握手,而關閉連接卻是四次揮手呢?

答案:這是因為服務端在LISTEN狀態下,收到建立連接請求的SYN報文后,把ACK和SYN放在一個報文里發送給客戶端。而關閉連接時,當收到對方的FIN報文時,僅僅表示對方不再發送數據了但是還能接收數據,己方也未必全部數據都發送給對方了,所以己方可以立即close,也可以發送一些數據給對方后,再發送FIN報文給對方來表示同意現在關閉連接,因此,己方ACK和FIN一般都會分開發送。

(3) 為什么TIME_WAIT狀態還需要等2MSL后才能返回到CLOSED狀態?

1.可靠的實現TCP全雙工鏈接的終止。

這是因為雖然雙方都同意關閉連接了,而且握手的4個報文也都協調和發送完畢,按理可以直接回到CLOSED狀態(就好比從SYN_SEND狀態到ESTABLISH狀態那樣);但是因為我們必須要假想網絡是不可靠的,你無法保證你最后發送的ACK報文會一定被對方收到,因此對方處于LAST_ACK狀態下的SOCKET可能會因為超時未收到ACK報文,而重發FIN報文,所以這個TIME_WAIT狀態的作用就是用來重發可能丟失的ACK報文。

2.允許老的重復的分節在網絡中消逝。

假 設在12.106.32.254的1500端口和206.168.1.112.219的21端口之間有一個TCP連接。我們關閉這個鏈接,過一段時間后在 相同的IP地址和端口建立另一個連接。后一個鏈接成為前一個的化身。因為它們的IP地址和端口號都相同。TCP必須防止來自某一個連接的老的重復分組在連 接已經終止后再現,從而被誤解成屬于同一鏈接的某一個某一個新的化身。為做到這一點,TCP將不給處于TIME_WAIT狀態的鏈接發起新的化身。既然 TIME_WAIT狀態的持續時間是MSL的2倍,這就足以讓某個方向上的分組最多存活msl秒即被丟棄,另一個方向上的應答最多存活msl秒也被丟棄。 通過實施這個規則,我們就能保證每成功建立一個TCP連接時。來自該鏈接先前化身的重復分組都已經在網絡中消逝了。

(4) 為什么不能用兩次握手進行連接?

我們知道,3次握手完成兩個重要的功能,既要雙方做好發送數據的準備工作(雙方都知道彼此已準備好),也要允許雙方就初始序列號進行協商,這個序列號在握手過程中被發送和確認。

現在把三次握手改成僅需要兩次握手,死鎖是可能發生的。作為例子,考慮計算機S和C之間的通信,假定C給S發送一個連接請求分組,S收到了這個分組,并發 送了確認應答分組。按照兩次握手的協定,S認為連接已經成功地建立了,可以開始發送數據分組。可是,C在S的應答分組在傳輸中被丟失的情況下,將不知道S 是否已準備好,不知道S建立什么樣的序列號,C甚至懷疑S是否收到自己的連接請求分組。在這種情況下,C認為連接還未建立成功,將忽略S發來的任何數據分 組,只等待連接確認應答分組。而S在發出的分組超時后,重復發送同樣的分組。這樣就形成了死鎖。

(5) TCP協議和UDP協議的區別是什么

  • TCP協議是有連接的,有連接的意思是開始傳輸實際數據之前TCP的客戶端和服務器端必須通過三次握手建立連接,會話結束之后也要結束連接。而UDP是無連接的
  • TCP協議保證數據按序發送,按序到達,提供超時重傳來保證可靠性,但是UDP不保證按序到達,甚至不保證到達,只是努力交付,即便是按序發送的序列,也不保證按序送到。
  • TCP協議所需資源多,TCP首部需20個字節(不算可選項),UDP首部字段只需8個字節。
  • TCP有流量控制和擁塞控制,UDP沒有,網絡擁堵不會影響發送端的發送速率
  • TCP是一對一的連接,而UDP則可以支持一對一,多對多,一對多的通信。
  • TCP面向的是字節流的服務,UDP面向的是報文的服務。
  • TCP介紹 和UDP介紹

(6) 三次握手建立連接時,發送方再次發送確認的必要性?

主要是為了防止已失效的連接請求報文段突然又傳到了B,因而產生錯誤。假定出現一種異常情況,即A發出的第一個連接請求報文段并沒有丟失,而是在某些網絡結 點長時間滯留了,一直延遲到連接釋放以后的某個時間才到達B,本來這是一個早已失效的報文段。但B收到此失效的連接請求報文段后,就誤認為是A又發出一次 新的連接請求,于是就向A發出確認報文段,同意建立連接。假定不采用三次握手,那么只要B發出確認,新的連接就建立了,這樣一直等待A發來數據,B的許多 資源就這樣白白浪費了。

(7) 四次揮手釋放連接時,等待2MSL的意義?

  1. 為了保證A發送的最有一個ACK報文段能夠到達B。這個ACK報文段有可能丟失,因而使處在LAST-ACK狀態的B收不到對已發送的FIN和ACK 報文段的確認。B會超時重傳這個FIN和ACK報文段,而A就能在2MSL時間內收到這個重傳的ACK+FIN報文段。接著A重傳一次確認。

  2. 就是防止上面提到的已失效的連接請求報文段出現在本連接中,A在發送完最有一個ACK報文段后,再經過2MSL,就可以使本連接持續的時間內所產生的所有報文段都從網絡中消失。

(8) 常見的應用中有哪些是應用TCP協議的,哪些又是應用UDP協議的,為什么它們被如此設計?

  • 以下應用一般或必須用udp實現?
    • 多播的信息一定要用udp實現,因為tcp只支持一對一通信。
    • 如果一個應用場景中大多是簡短的信息,適合用udp實現,因為udp是基于報文段的,它直接對上層應用的數據封裝成報文段,然后丟在網絡中,如果信息量太大,會在鏈路層中被分片,影響傳輸效率。
    • 如果一個應用場景重性能甚于重完整性和安全性,那么適合于udp,比如多媒體應用,缺一兩幀不影響用戶體驗,但是需要流媒體到達的速度快,因此比較適合用udp
    • 如果要求快速響應,那么udp聽起來比較合適
    • 如果又要利用udp的快速響應優點,又想可靠傳輸,那么只能考上層應用自己制定規則了。
    • 常見的使用udp的例子:ICQ,QQ的聊天模塊。
HTTP 請求響應常見狀態碼
100~199:表示成功接收請求,要求客戶端繼續提交下一次請求才能完成整個處理過程。
200~299:表示成功接收請求并已完成整個處理過程。常用200
300~399:為完成請求,客戶需進一步細化請求。例如:請求的資源已經移動一個新地址、常用302(意味著你請求我,我讓你去找別人),307和304(我不給你這個資源,自己拿緩存)
400~499:客戶端的請求有錯誤,常用404(意味著你請求的資源在web服務器中沒有)403(服務器拒絕訪問,權限不夠)
500~599:服務器端出現錯誤,常用500

本文參考
理論經典:TCP協議的3次握手與4次揮手過程詳解
TCP三次握手四次揮手詳解
非常感謝上述作者.


相關資料參考
理論經典:TCP協議的3次握手與4次揮手過程詳解

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,197評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,415評論 3 415
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,104評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,884評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,647評論 6 408
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,130評論 1 323
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,208評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,366評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,887評論 1 334
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,737評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,939評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,478評論 5 358
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,174評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,586評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,827評論 1 283
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,608評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,914評論 2 372

推薦閱讀更多精彩內容