劍指Offer(網絡)——TCP三次握手

簡單來介紹一下傳輸控制協議TCP:

  1. TCP協議是面向連接的、可靠的、基於字節流的傳輸層通信協議;
  2. 當數據傳輸的時候,應用層向TCP發送數據流,然後TCP會將應用層的數據流分割成報文段併發送給目標節點的TCP層;
  3. TCP爲了保證不丟包就給每一個包一個序號(Sequence Number),同時序號也保證對方接受數據的時候順序是一定的;
  4. 當對方收到數據的時候回覆一個ACK去確認,如果在合理的時延之內沒有收到數據就會認爲已丟失也就會將其重傳;
  5. TCP所使用的是奇偶校驗覈函數檢驗數據在傳輸的過程中是否有錯誤,在發送和接收的時候都要計算校驗和。

介紹一下TCP報文傳輸時候常見的flag:

  1. URG:緊急指針標誌(1表示緊急指針有效,0表示忽略緊急指針);
  2. ACK:確認序號標誌(1表示確認號有效,0表示不需要確認);
  3. PSH:push標誌(1標記的數據代表提示對方應該快速將信息發給應用程序,0相反);
  4. RST:重置連接標誌(拒絕連接請求,出意外了就用);
  5. SYN:同步序號,用於建立連接過程(在連接請求中,SYN=1,ACK=0沒有使用捎帶的確認域,而SYN=1,ACK=1代表連接應答捎帶一個確認域);
  6. FIN:finish標誌,代表釋放連接(爲1是代表發送方已經沒有數據要發送了)。

一個應用程序渴望通過TCP連接另一個應用程序的時候會發送一個通信請求,這個請求必須被送到一個確切的地址,雙方握手之後,TCP將在兩個應用程序之間建立一個全雙工的通信將佔用兩個計算機的通信線路直到斷開連接。“握手”是爲了建立連接,TCP的三次握手的流程如下:
在這裏插入圖片描述
描述一下過程:

  1. 開始的時候A和B處於Close的狀態,假設主動打開的是客戶端,被動打開連接的是服務端;
  2. 開始的時候TCP服務器進程先創建傳輸控制塊PCB,時刻準備接受其他客戶進程發送過來的連接請求,然後就進入了LISTEN的狀態;
  3. 此時,我們的TCP Client也是先創建一個傳輸控制塊PCB然後向服務器發送請求連接的報文,並且攜帶的初始序號sequence=x,SYN=1,這時候,TCP Client進入了一個SYN-SENT的狀態,也就是同步已發送,此時發送過去的數據包被稱爲SYN報文段,是不可以發送數據的但是要消耗掉一個序號這就是第一次握手;
  4. 當我們的服務器接收到請求報文之後,如果同意連接,就發送確認報文,確認報文中包含SYN=1,ACK=1,序列號sequence=y,返回號ack由於上面發送過來了一個sequence=x作爲迴應,應該回應一個和x相關的信息,而且上面難點報文消耗掉了一個序號,所以ack=x+1 ,此時服務器進入SYN-RCVD,同步收到的狀態,這個報文也是不能攜帶數據的,並且同樣需要消耗掉一個序號,這就是第二次握手;
  5. 那麼,當TCP Client收到了確認報文之後,還要向服務器給出一個確認,確認的報文攜帶的flag是ACK=1。sequence=x+1,ack=y+1,這裏的ack=y+1是因爲,之前發送過來的sequence是y,所以作爲迴應,就必須和y相關,又不能和y重複,就是y+1了,而且之前我們發送過去的seq是x,服務器返回過來的時候是x+1,那麼再去確認的時候,就也得加一了,所以sequence=x+1,並且,這個報文段是可以攜帶數據的,前兩個都是不可以攜帶數據的,當然,它也可以不攜帶數據,如果不攜帶數據,就不會消耗序號,這就是第三次握手;
  6. 服務器收到客戶端的確認之後,也會進入到ESTABLISH的狀態,此後雙方就可以開始通信。

爲什麼我們需要三次握手才能將連接建立起來呢?

主要是爲了初始化Sequence Number的初始值,通信的雙方要通知對方自己初始化的Sequence Number,這個序號要作爲以後數據通信的序號,讓應用層接收到數據的時候,不會因爲網絡上的傳輸而導致順序錯亂,也就是說,TCP利用Sequence Number來拼接數據,所以這就是我們發送第三次握手的原因,讓服務端知道客戶端已經收到了服務端的Sequence Number。

首次握手有一個隱患——SYN超時,問題起因如下

如果Server端收到了Client端的SYN,然後回覆SYN-ACK的時候未收到ACK確認,此時Client還下線了,那麼連接就會處於一箇中間狀態,也就是失敗,於是Server端那邊會不斷重試直到超時,Linux默認等待63秒後纔會斷開連接。那麼,爲什麼是63秒呢,其實,說是63秒,不如說是5次,實際上是在 1 2 4 8 16 32秒的時候,都會進行重傳,第一秒的時候是第一次發送,所以不算數,也就是說,當這五次重傳,還是沒有接收到迴應,就算是斷開連接了。

那麼,這樣的後果是什麼呢?

將會遭到SYN Flood,於是我們再來解釋一下針對SYN FLOOD的防護措施。

這個事情的原理是這樣的,在重試的那63秒內,惡意的程序將SYN對應連接隊列耗盡,使之不能處理正常的握手請求。在linux下,是有一定解決措施的,當SYN隊列滿了之後,通過tcp_syncookies參數將會回發SYN Cookie,如果要是正常的連接,那麼Client就會回發一個SYN Cookie,直接建立連接。

如果一段時間之後,Client出現了故障怎麼辦?

TCP默認使用保活機制,在規定的時間內,向對方發送保活探測報文,如果沒有收到響應,就會繼續發送,直到嘗試的次數達到保活探測數仍未收到響應,就中斷連接。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章