三次握手和四次揮手

前言

三次握手和四次揮手不少小夥伴老是記不住,包括我在內,以爲ACK,SYN,ack 是啥嗎,怎麼記得住他們的狀態,值爲多少?這篇文章將帶你清晰認識三次揮手和四次握手的過程。html

1. 三次握手

三次握手(Three-way Handshake)其實就是指創建一個TCP鏈接時,須要客戶端和服務器總共發送3個包。進行三次握手的主要做用就是爲了確認雙方的接收能力和發送能力是否正常、指定本身的初始化序列號爲後面的可靠性傳送作準備。實質上其實就是鏈接服務器指定端口,創建TCP鏈接,並同步鏈接雙方的序列號和確認號,交換TCP窗口大小信息。git

1.1 三次握手詳解

官話套話說完了,咱們來說一下它的過程。github

三次握手

其實之因此要進行三次握手的緣由就是爲了:客戶端與服務端都必須確保本身和對方都能接發正常。面試

第一次握手(客戶端-->服務端): 客戶端什麼都不用確認,服務端確認:對方發送正常。bash

第二次握手(服務端-->客戶端): 客戶端確認:本身發送正常、接收正常(經過本身發送接收可確認),對方發送正常、接收正常(客戶端確認完畢);服務端確認:本身接收正常,對方發送正常。服務器

第三次握手(客戶端-->服務端): 服務端確認:本身接發正常,對方接發正常。cookie

是否是這樣理解就簡單多了,而報文中的參數設置就是爲了「確認」的保障。網絡

如今咱們再來看看參數設置:併發

TCP報文段格式

那一堆的大寫參數,UCG、ACK、SYN等,當置爲1時,即有效,爲0時無效。spa

認真了,硬核來了!!!

三次握手

第一次握手(SYN=1, seq=x):

客戶端發送一個 TCP 的 SYN 標誌位置1的包,指明客戶端打算鏈接的服務器的端口,以及初始序號 X,保存在包頭的序列號(Sequence Number)字段裏。

發送完畢後,客戶端進入 SYN_SEND 狀態。

第二次握手(SYN=1, ACK=1, seq=y, ACKnum=x+1):

服務器發回確認包(ACK)應答。即 SYN 標誌位和 ACK 標誌位均爲1。服務器端選擇本身 ISN 序列號,放到 Seq 域裏,同時將確認序號(Acknowledgement Number)設置爲客戶的 ISN 加1,即X+1。 發送完畢後,服務器端進入 SYN_RCVD 狀態。

第三次握手(ACK=1,ACKnum=y+1):

客戶端再次發送確認包(ACK),SYN 標誌位爲0,ACK 標誌位爲1,而且把服務器發來 ACK 的序號字段+1,放在肯定字段中發送給對方,而且在數據段放寫ISN的+1

發送完畢後,客戶端進入 ESTABLISHED 狀態,當服務器端接收到這個包時,也進入 ESTABLISHED 狀態,TCP 握手結束。

1.2 爲何須要三次握手,兩次握手行不行

上面講了三次握手過程,咱們來設想一下,兩次握手會發生什麼?

只採起兩次握手,則表現爲當客戶端發出請求後,收到確認就創建鏈接。

如客戶端發出鏈接請求,但因鏈接請求報文丟失而未收到確認,因而客戶端再重傳一次鏈接請求。後來收到了確認,創建了鏈接。數據傳輸完畢後,就釋放了鏈接,客戶端共發出了兩個鏈接請求報文段,其中第一個丟失,第二個到達了服務端,可是第一個丟失的報文段只是在某些網絡結點長時間滯留了,延誤到鏈接釋放之後的某個時間纔到達服務端,此時服務端誤認爲客戶端又發出一次新的鏈接請求,因而就向客戶端發出確認報文段,贊成創建鏈接,不採用三次握手,只要服務端發出確認,就創建新的鏈接了,此時客戶端忽略服務端發來的確認,也不發送數據,則服務端一致等待客戶端發送數據,浪費資源。

1.3 什麼是半鏈接隊列

服務器第一次收到客戶端的 SYN 以後,就會處於 SYN_RCVD 狀態,此時雙方尚未徹底創建其鏈接,服務器會把此種狀態下請求鏈接放在一個隊列裏,咱們把這種隊列稱之爲半鏈接隊列。

固然還有一個全鏈接隊列,就是已經完成三次握手,創建起鏈接的就會放在全鏈接隊列中。若是隊列滿了就有可能會出現丟包現象。

1.4 SYN-ACK 重傳次數

服務器發送完SYN-ACK包,若是未收到客戶確認包,服務器進行首次重傳,等待一段時間仍未收到客戶確認包,進行第二次重傳。若是重傳次數超過系統規定的最大重傳次數,系統將該鏈接信息從半鏈接隊列中刪除。

注意,每次重傳等待的時間不必定相同,通常會是指數增加,例如間隔時間爲 1s,2s,4s,8s…

1.5 三次握手過程當中能夠攜帶數據嗎

其實第三次握手的時候,是能夠攜帶數據的。可是,第一次、第二次握手不能夠攜帶數據

爲何這樣呢?你們能夠想一個問題,假如第一次握手能夠攜帶數據的話,若是有人要惡意攻擊服務器,那他每次都在第一次握手中的 SYN 報文中放入大量的數據。由於攻擊者根本就不理服務器的接收、發送能力是否正常,而後瘋狂着重複發 SYN 報文的話,這會讓服務器花費不少時間、內存空間來接收這些報文。

也就是說,第一次握手不能夠放數據,其中一個簡單的緣由就是會讓服務器更加容易受到攻擊了。而對於第三次的話,此時客戶端已經處於 ESTABLISHED 狀態。對於客戶端來講,他已經創建起鏈接了,而且也已經知道服務器的接收、發送能力是正常的了,因此能攜帶數據也沒啥毛病。

1.6 SYN攻擊是什麼

服務器端的資源分配是在二次握手時分配的,而客戶端的資源是在完成三次握手時分配的,因此服務器容易受到SYN洪泛攻擊。SYN攻擊就是Client在短期內僞造大量不存在的IP地址,並向Server不斷地發送SYN包,Server則回覆確認包,並等待Client確認,因爲源地址不存在,所以Server須要不斷重發直至超時,這些僞造的SYN包將長時間佔用未鏈接隊列,致使正常的SYN請求由於隊列滿而被丟棄,從而引發網絡擁塞甚至系統癱瘓。SYN 攻擊是一種典型的 DoS/DDoS 攻擊

檢測 SYN 攻擊很是的方便,當你在服務器上看到大量的半鏈接狀態時,特別是源IP地址是隨機的,基本上能夠判定這是一次SYN攻擊。在 Linux/Unix 上可使用系統自帶的 netstats 命令來檢測 SYN 攻擊。

netstat -n -p TCP | grep SYN_RECV

常見的防護 SYN 攻擊的方法有以下幾種

  • 縮短超時(SYN Timeout)時間
  • 增長最大半鏈接數
  • 過濾網關防禦
  • SYN cookies技術

2. 四次揮手

2.1 四次揮手詳解

爲何要叫「揮手」呢?

我猜,這個過程就跟人與人交流同樣,須要揮手 say goodbye,hhh!

四次揮手過程比三次揮手要簡單一點,由於很好理解,就像我和女友打電話同樣。

① 我說:我說完了,你還有什麼要跟我說的嗎?

② 她說:我知道了。

③ 她接着叮囑我:你記得想我哦。。。。。。(又說了一堆,)我說完了。

④ 我說:知道了,掛了哦!
複製代碼

而後就結束了通話了。四次揮手就結束了,是否是就像通話過程。

官方一點的講解來了:

終止一個鏈接要通過四次揮手(也有將四次揮手叫作四次握手的)。這由TCP的半關閉(half-close)形成的。所謂的半關閉,其實就是TCP提供了鏈接的一端在結束它的發送後還能接收來自另外一端數據的能力。

四次握手

TCP 的鏈接的拆除須要發送四個包,所以稱爲四次揮手(Four-way handshake),客戶端或服務器都可主動發起揮手動做。

剛開始雙方都處於 ESTABLISHED 狀態,假如是客戶端先發起關閉請求。四次揮手的過程以下:

  • 第一次揮手:客戶端發送一個 FIN 報文,報文中會指定一個序列號。此時客戶端處於 FIN_WAIT1 狀態。

即發出鏈接釋放報文段(FIN=1,序號seq=u),並中止再發送數據,主動關閉TCP鏈接,進入FIN_WAIT1(終止等待1)狀態,等待服務端的確認。

  • 第二次揮手:服務端收到 FIN 以後,會發送 ACK 報文,且把客戶端的序列號值 +1 做爲 ACK 報文的序列號值,代表已經收到客戶端的報文了,此時服務端處於 CLOSE_WAIT 狀態。

即服務端收到鏈接釋放報文段後即發出確認報文段(ACK=1,確認號ack=u+1,序號seq=v),服務端進入CLOSE_WAIT(關閉等待)狀態,此時的TCP處於半關閉狀態,客戶端到服務端的鏈接釋放。客戶端收到服務端的確認後,進入FIN_WAIT2(終止等待2)狀態,等待服務端發出的鏈接釋放報文段。

  • 第三次揮手:若是服務端也想斷開鏈接了,和客戶端的第一次揮手同樣,發給 FIN 報文,且指定一個序列號。此時服務端處於 LAST_ACK 的狀態。

即服務端沒有要向客戶端發出的數據,服務端發出鏈接釋放報文段(FIN=1,ACK=1,序號seq=w,確認號ack=u+1),服務端進入LAST_ACK(最後確認)狀態,等待客戶端的確認。

  • 第四次揮手:客戶端收到 FIN 以後,同樣發送一個 ACK 報文做爲應答,且把服務端的序列號值 +1 做爲本身 ACK 報文的序列號值,此時客戶端處於 TIME_WAIT 狀態。須要過一陣子以確保服務端收到本身的 ACK 報文以後纔會進入 CLOSED 狀態,服務端收到 ACK 報文以後,就處於關閉鏈接了,處於 CLOSED 狀態。

即客戶端收到服務端的鏈接釋放報文段後,對此發出確認報文段(ACK=1,seq=u+1,ack=w+1),客戶端進入TIME_WAIT(時間等待)狀態。此時TCP未釋放掉,須要通過時間等待計時器設置的時間2MSL後,客戶端才進入CLOSED狀態。

收到一個FIN只意味着在這一方向上沒有數據流動。客戶端執行主動關閉並進入TIME_WAIT是正常的,服務端一般執行被動關閉,不會進入TIME_WAIT狀態。

2.2 揮手爲何要進行四次

其實看了上面講解,大致也知道爲何了。

四次握手

當服務端收到客戶端的SYN鏈接請求報文後,能夠直接發送SYN+ACK報文。其中ACK報文是用來應答的,SYN報文是用來同步的。可是關閉鏈接時,當服務端收到FIN報文時,極可能並不會當即關閉SOCKET,因此只能先回復一個ACK報文,告訴客戶端,「 你發的FIN報文我收到了 」。只有等到我服務端全部的報文都發送完了,我才能發送FIN報文,所以不能一塊兒發送。故須要四次揮手。

2.3 2MSL等待狀態

TIME_WAIT狀態也成爲2MSL等待狀態。每一個具體TCP實現必須選擇一個報文段最大生存時間 MSL(Maximum Segment Lifetime),它是任何報文段被丟棄前在網絡內的最長時間。這個時間是有限的,由於TCP報文段以IP數據報在網絡內傳輸,而IP數據報則有限制其生存時間的TTL字段

對一個具體實現所給定的MSL值,處理的原則是:當TCP執行一個主動關閉,併發回最後一個ACK,該鏈接必須在TIME_WAIT狀態停留的時間爲2倍的MSL。這樣可以讓TCP再次發送最後的ACK以防這個ACK丟失(另外一端超時並重發最後的FIN)。

這種2MSL等待的另外一個結果是這個TCP鏈接在2MSL等待期間,定義這個鏈接的插口(客戶的IP地址和端口號,服務器的IP地址和端口號)不能再被使用。這個鏈接只能在2MSL結束後才能再被使用。

簡單的來講,就是,IP報文段限制了其生存時間,爲了儘量的保證收到報文,咱們採起重傳,因此須要2MSL。

2.4 四次揮手釋放鏈接時,等待2MSL的意義

MSL是Maximum Segment Lifetime的英文縮寫,可譯爲「最長報文段壽命」,它是任何報文在網絡上存在的最長時間,超過這個時間報文將被丟棄。

爲了保證客戶端發送的最後一個ACK報文段可以到達服務器。由於這個ACK有可能丟失,從而致使處在LAST-ACK狀態的服務器收不到對FIN-ACK的確認報文。服務器會超時重傳這個FIN-ACK,接着客戶端再重傳一次確認,從新啓動時間等待計時器。最後客戶端和服務器都能正常的關閉。假設客戶端不等待2MSL,而是在發送完ACK以後直接釋放關閉,一但這個ACK丟失的話,服務器就沒法正常的進入關閉鏈接狀態。

兩個理由:

  • 保證客戶端發送的最後一個ACK報文段可以到達服務端。 這個ACK報文段有可能丟失,使得處於LAST-ACK狀態的B收不到對已發送的FIN+ACK報文段的確認,服務端超時重傳FIN+ACK報文段,而客戶端能在2MSL時間內收到這個重傳的FIN+ACK報文段,接着客戶端重傳一次確認,從新啓動2MSL計時器,最後客戶端和服務端都進入到CLOSED狀態,若客戶端在TIME-WAIT狀態不等待一段時間,而是發送完ACK報文段後當即釋放鏈接,則沒法收到服務端重傳的FIN+ACK報文段,因此不會再發送一次確認報文段,則服務端沒法正常進入到CLOSED狀態。

  • 防止「已失效的鏈接請求報文段」出如今本鏈接中。 客戶端在發送完最後一個ACK報文段後,再通過2MSL,就可使本鏈接持續的時間內所產生的全部報文段都從網絡中消失,使下一個新的鏈接中不會出現這種舊的鏈接請求報文段。

2.5 爲何TIME_WAIT狀態須要通過2MSL才能返回到CLOSE狀態

理論上,四個報文都發送完畢,就能夠直接進入CLOSE狀態了,可是可能網絡是不可靠的,有可能最後一個ACK丟失。因此TIME_WAIT狀態就是用來重發可能丟失的ACK報文。

3. 小結&參考資料

小結

TCP狀態變遷圖

如今是否是對於TCP鏈接的三次握手和四次揮手比較清晰了,hhh。 咱們也該揮手了,FIN = 1。

參考資料

相關文章
相關標籤/搜索