簡單來介紹一下傳輸控制協定TCP:
- TCP協定是面向連接配接的、可靠的、基于位元組流的傳輸層通信協定;
- 當資料傳輸的時候,應用層向TCP發送資料流,然後TCP會将應用層的資料流分割成封包段并發送給目标節點的TCP層;
- TCP為了保證不丢包就給每一個包一個序号(Sequence Number),同時序号也保證對方接受資料的時候順序是一定的;
- 當對方收到資料的時候回複一個ACK去确認,如果在合理的時延之内沒有收到資料就會認為已丢失也就會将其重傳;
- TCP所使用的是奇偶校驗核函數檢驗資料在傳輸的過程中是否有錯誤,在發送和接收的時候都要計算校驗和。
介紹一下TCP封包傳輸時候常見的flag:
- URG:緊急指針标志(1表示緊急指針有效,0表示忽略緊急指針);
- ACK:确認序号标志(1表示确認号有效,0表示不需要确認);
- PSH:push标志(1标記的資料代表提示對方應該快速将資訊發給應用程式,0相反);
- RST:重置連接配接标志(拒絕連接配接請求,出意外了就用);
- SYN:同步序号,用于建立連接配接過程(在連接配接請求中,SYN=1,ACK=0沒有使用捎帶的确認域,而SYN=1,ACK=1代表連接配接應答捎帶一個确認域);
- FIN:finish标志,代表釋放連接配接(為1是代表發送方已經沒有資料要發送了)。
一個應用程式渴望通過TCP連接配接另一個應用程式的時候會發送一個通信請求,這個請求必須被送到一個确切的位址,雙方握手之後,TCP将在兩個應用程式之間建立一個全雙工的通信将占用兩個計算機的通信線路直到斷開連接配接。“握手”是為了建立連接配接,TCP的三次握手的流程如下:

描述一下過程:
- 開始的時候A和B處于Close的狀态,假設主動打開的是用戶端,被動打開連接配接的是服務端;
- 開始的時候TCP伺服器程序先建立傳輸控制塊PCB,時刻準備接受其他客戶程序發送過來的連接配接請求,然後就進入了LISTEN的狀态;
- 此時,我們的TCP Client也是先建立一個傳輸控制塊PCB然後向伺服器發送請求連接配接的封包,并且攜帶的初始序号sequence=x,SYN=1,這時候,TCP Client進入了一個SYN-SENT的狀态,也就是同步已發送,此時發送過去的資料包被稱為SYN封包段,是不可以發送資料的但是要消耗掉一個序号這就是第一次握手;
- 當我們的伺服器接收到請求封包之後,如果同意連接配接,就發送确認封包,确認封包中包含SYN=1,ACK=1,序列号sequence=y,傳回号ack由于上面發送過來了一個sequence=x作為回應,應該回應一個和x相關的資訊,而且上面難點封包消耗掉了一個序号,是以ack=x+1 ,此時伺服器進入SYN-RCVD,同步收到的狀态,這個封包也是不能攜帶資料的,并且同樣需要消耗掉一個序号,這就是第二次握手;
- 那麼,當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,并且,這個封包段是可以攜帶資料的,前兩個都是不可以攜帶資料的,當然,它也可以不攜帶資料,如果不攜帶資料,就不會消耗序号,這就是第三次握手;
- 伺服器收到用戶端的确認之後,也會進入到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預設使用保活機制,在規定的時間内,向對方發送保活探測封包,如果沒有收到響應,就會繼續發送,直到嘗試的次數達到保活探測數仍未收到響應,就中斷連接配接。