1. 程式人生 > >TCP連線管理、可靠傳輸機制、提升傳輸效能機制

TCP連線管理、可靠傳輸機制、提升傳輸效能機制

TCP協議格式

TCP全稱為“傳輸控制協議”,是傳輸層一種重要的協議

TCP協議段格式 十六位源埠號、十六位目的埠號、三十二位序號、三十二位確認序號、四位首部長度、保留六位、十六位視窗指標大小、十六位校驗和、十六位緊急指標、資料。

  • 源埠號/目的埠號,記錄了資料的傳遞方向以及目標

  • 4位TCP報頭長度:表示該條資料有多少個4位元組,所以TCP最大長度為15*4=60

  • 32為序列號和32位確認序列號

  • 6位標誌位: URG:緊急指標是否有效 ACK:確認號是否有效 PSH:提示接收端應用程式立即從tcp緩衝區讀走 RST:對方要求重新建立連線,我們把攜帶RST標示的稱為復位報文段 SYN:請求建立連線,;我們把攜帶SYN識別符號的稱為同步報文段 FIN:通知對方要關閉連線,我們稱攜帶FIN標識的為結束報文段

  • 十六位視窗號:滑動視窗的大小

  • 十六位校驗和:傳送端填充,CRC校驗,接受端校驗和不光包含TCP首部,也包含資料部分。

  • 十六位緊急指標:標識哪部分資料是緊急資料

  • 40位元組頭部選項

TCP三次握手建立連線過程

在這裡插入圖片描述 伺服器狀態轉化 [CLOSED -> LISTEN] 伺服器端呼叫用listen後進入入LISTEN狀態, 等待客戶端連線; [LISTEN -> SYN_RCVD] 一一旦監聽到連線請求(同步報文文段), 就將該連線放入入核心等待佇列中, 並向 客戶端傳送SYN確認報文文. [SYN_RCVD -> ESTABLISHED] 服務端一一旦收到客戶端的確認報文文, 就進入入ESTABLISHED狀態, 可以進行行讀寫資料了. [ESTABLISHED -> CLOSE_WAIT] 當客戶端主動關閉連線(呼叫用close), 伺服器會收到結束報文文段, 伺服器返回確認報文文段並進入入CLOSE_WAIT; [CLOSE_WAIT -> LAST_ACK] 進入入CLOSE_WAIT後說明伺服器準備關閉連線(需要處理完之前的 資料); 當伺服器真正呼叫用close關閉連線時, 會向客戶端傳送FIN, 此時伺服器進入入LAST_ACK狀態, 等待最後一一個ACK到來(這個ACK是客戶端確認收到了FIN) [LAST_ACK -> CLOSED] 伺服器收到了對FIN的ACK, 徹底關閉連線.

客戶端狀態轉化 [CLOSED -> SYN_SENT] 客戶端呼叫用connect, 傳送同步報文文段;[SYN_SENT -> ESTABLISHED] connect呼叫用成功, 則進入入ESTABLISHED狀態, 開始讀寫資料; [ESTABLISHED -> FIN_WAIT_1] 客戶端主動呼叫用close時, 向伺服器傳送結束報文文段, 同時進入入 FIN_WAIT_1; [FIN_WAIT_1 -> FIN_WAIT_2] 客戶端收到伺服器對結束報文文段的確認, 則進入入FIN_WAIT_2, 開始 等待伺服器的結束報文文段; [FIN_WAIT_2 -> TIME_WAIT] 客戶端收到伺服器發來的結束報文文段, 進入入TIME_WAIT, 併發出 LAST_ACK; [TIME_WAIT -> CLOSED] 客戶端要等待一一個2MSL(Max Segment Life, 報文最大生存時間)的時間, 才會進入入CLOSED狀態

關於等待兩個MSL時間的解釋 MSL時間,即報文最大生存時間,在網路上的報文都是有存活時間的,當報文在網路上傳輸的時間超過了這個報文的存活時間,報文就會在網路中被丟棄。當客戶端傳送完一個ACK包給伺服器之後變成TIME_WAIT狀態,這時候可能ACK並沒有傳送到伺服器端,這時候經歷的時間是一個MSL時間,ACK丟棄在網路之中,然後有超時重傳機制的伺服器會再次傳送一個FIN包,這樣又會經歷一個MSL時間。為了防止下一個客戶端被之前客戶端的報文所影響,所以必須等待兩個MSL時間。(客戶端和服務端的情況可能發生變化,在特殊情況下)

解決TIME_WAIT狀態引起的bind失敗的方法 採用setsockopt()來設定socket描述符的SOL_REUSEADDR 為1 在 socket 與 bind 之間插入如下程式碼:

int opt = 1;
setsockopt(lis_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));

TCP傳輸的特點:

  • 有連線
  • 可靠傳輸
  • 面向位元組流

TCP保證可靠傳輸的機制

  • 確認應答機制:對每次傳送的資料報需要確認到達
  • 超時重傳機制:對沒收到的資料(即未收到確認到達的資料報)進行重新發送
  • 32位序號與32位確認序號:保證資料傳輸的有序性

確認應答(ACK)機制 每一個ACK都會有對應的確認序號,意思是告訴傳送者已經收到了那些資料,下一條資料你從哪裡開始發 在這裡插入圖片描述

超時重傳機制 超時重傳是TCP協議保證資料可靠性的另一個重要機制,其原理是在傳送某一個數據以後就開啟一個計時器,在一定時間內如果沒有得到傳送的資料報的ACK報文,那麼就重新發送資料,直到傳送成功為止。

超時重傳時間RTO是根據往返時間RTT(Karn演算法)推匯出來的一個合適的時間。 在這裡插入圖片描述 Linux中最大超時時間以500ms為一個單位進行控制,每次判定超時重發的超時時間都是500ms的整數倍。 如果重發一一次之後, 仍然得不到應答, 等待 2×500ms 後再進行行重傳. 如果仍然得不到應答, 等待 4×500ms 進行行重傳. 依次類推, 以指數形式遞增. 累計到一定的重傳次數, TCP認為網路或者對端主機出現異常, 強制關閉連線

TCP為了保證可靠傳輸採用了一系列機制,但是這些機制背後帶來的是效能的下降,所以有設定了一系列的機制來提高傳輸效能。

提高傳輸效能的機制

  • 滑動視窗機制與快速重傳機制
  • 流量控制機制
  • 擁塞控制機制
  • 延遲應答機制
  • 捎帶應答機制

滑動視窗機制 當採取傳統的傳送一條資料等待回覆,收到回覆再發送一條資料的機制來看,雖然保證了可靠傳輸的條件之一,但是效率十分底下,所以採用滑動視窗機制來批量傳送資料

視窗大小是指無需等待應答二可以直接繼續傳送的資料的最大值,先假設視窗大小為4段(4000位元組),傳送前四段的時候無需等待ACK回覆,直接傳送。收到第一個ACK之後視窗向後滑動,繼續傳送第五個段的資料,以此類推。作業系統核心需要維護滑動視窗,需要開闢一段快取區,叫做傳送緩衝區,來記錄當前哪些資料還沒有應答,應答的資料在緩衝區就會被刪除。視窗的大小也就是網路吞吐率的大小。

快速重傳機制 在滑動視窗機制中有兩種比較特殊的情況: 1.資料傳輸來,服務端返回ACK的時候在網路中丟失。 2.資料傳輸的途中直接丟失。

面對情況一: ACK丟失之後可以通過後續的ACK來確定,即第二段的ACK丟失,但是第三段的ACK已經被客戶端所接收到,預設第二段報文也被送達到了。

面對情況二: 資料報在丟失之後,連續傳送三次丟失報文的資訊 如: 第一段報文丟失,而此時已經發送到了第四段的報文,再次傳送的時候會一直髮送第一段的請求ACK,知道第一段被重新發送才會回覆第四段的的ACK。   流量控制 接收端的資料處理速度是有限的額,如果傳送的太快,會導致接受緩衝區被塞滿,接下來到達的報文都會被丟棄,再進行重傳,降低了效能。 TCP通過流量控制來決定傳送端的資料,這個機制就是 流量控制機制 即每次進行ACK回覆的時候都會將接收端的大小放入TCP首部的視窗大小欄位當中,通過ACK告訴傳送端 視窗欄位越大代表網路吞吐量越高,當緩衝區還剩餘很大的空間的時候,視窗大小欄位的值會比較大,而當緩衝區快滿的時候,就會返回一個較小的值,來實現動態控制流量。如果接收端緩衝區滿了, 就會將視窗置為0; 這時傳送方不再發送資料, 但是需要定期傳送一個視窗   擁塞控制  雖然有滑動視窗機制來提高發送資料量,但是在起始階段,也就是不知網路條件的狀況下就開始大量傳輸資料就有可能造成丟包和大量重傳,所以需要引入一個慢啟動的裝置來摸清當前網路狀態。 一開始定義阻塞視窗的大小十分小,每次成功傳輸都以指數級增長,到達視窗的閾值之後會放緩增長速度,當出現丟包狀況時,視窗的值立馬降為初始值,而閾值變為原來的一半,這個機制能有效的保證在不同網路狀況下的傳輸都變得高效    延遲應答  接收到的主機立刻返回ACK應答,這時候可能視窗會比較小,所以可以為了提高網路的吞吐量的情況下適當的延遲應答,讓返回的視窗大小盡可能的變大。 具體的數量和超時時間, 依作業系統不同也有差異; 超時時間取200ms;    捎帶應答 全雙工服務(Full Duplex Communication) 一個TCP連線允許資料在任何一個方向流動,並允許任何一個應用程式在任何時刻傳送資料。即當兩個程序 A 和 B 建立連線後,任何一方均能傳送資料給另一方。當分組從 A 發往B 時,可攜帶對 B 發來資料的確認。同理,當分組從 B 發往 A 時,可攜帶對 A 發來資料的確認。即採用捎帶確認的機制。

面向位元組流 建立一個TCP的socket, 同時在核心中建立一個 傳送緩衝區 和一個 接收緩衝區; 呼叫write時, 資料會先寫入傳送緩衝區中; 如果傳送的位元組數太長, 會被拆分成多個TCP的資料包發出; 如果傳送的位元組數太短, 就會先在緩衝區裡等待, 等到緩衝區長度差不多了, 或者其他合適的時機發送出去; 接收資料的時候, 資料也是從網絡卡驅動程式到達核心的接收緩衝區然後應用用程式可以呼叫用read從接收緩衝區拿資料; 另一方面, TCP的一個連線, 既有傳送緩衝區, 也有接收緩衝區, 那麼對於這一個連線, 既可以讀資料,也可以寫資料. 這個概念叫做 全雙工由於緩衝區的存在, TCP程式的讀和寫不需要一一匹配, 例如: 寫100個位元組資料時, 可以呼叫一次write寫100個位元組, 也可以呼叫用100次write, 每次寫一個位元組;讀100個位元組資料時, 也完全不需要考慮寫的時候是怎麼寫的, 既可以一次read 100個位元組, 也可以一次read一個位元組, 重複100次;

粘包問題  面向位元組流的報文無法區分資料與資料之間的界限,所以要解決粘包問題,可以從以下幾個方法中來看:

  • 規定包的長度
  • 在包的頭部加上該包的長度
  • 確定包與包之間的分隔符

基於TCP的應用層知名協議

  • HTTP
  • HTTPS
  • SSH
  • Telnet
  • FTP
  • SMTP