1. 程式人生 > >TCP傳輸控制協議分析

TCP傳輸控制協議分析

簡介

        TCP(Transmission Control Protocol)即傳輸控制協議。是一種面向連線的、可靠的、基於位元組流的傳輸層通訊協議,由IETF的RFC 793定義。在簡化的計算機網路OSI模型中,它完成第四層傳輸層所指定的功能,另一個重要的傳輸協議。在因特網協議族中,TCP層是位於IP層之上,應用層之下的中間層。不同主機的應用層之間經常需要可靠的、像管道一樣的連線,但是IP層不提供這樣的流機制,而是提供不可靠的包交換。應用層向TCP層傳送用於網間傳輸的、用8位位元組表示的資料流,然後TCP把資料流分割槽成適當長度的報文段(通常受該計算機連線的網路的資料鏈路層的最大傳輸單元(MTU)的限制)。之後TCP把結果包傳給IP層,由它來通過網路將包傳送給接收端實體的TCP層。
主要特點:1.面向連線 2.一對一傳輸 3.可靠交付 4.只支援全雙工通訊 5.面向位元組流 6.比UDP協議首部開銷大

封包格式及各欄位分析

封包格式

欄位分析

(1)源埠:佔2位元組、標明源埠
(2)目的埠:佔2位元組、標明目的埠
(3)序號:佔4位元組、序號範圍是[0,2^32-1,(即4294967296)個序號。序號增加到2^32-1後,下一個序號就又回到0。也就是說,序號使用mod2^32運算。TCP是面向位元組流的。在一個TCP連線中傳送的位元組流中的每一個位元組都按順序編號。整個要傳送的位元組流的起始序號必須在連線建立時設定。首部中的序號欄位值則指的是本報文段所傳送的資料的第一個位元組的序號。例如,一報文段的序號欄位值是301,而攜帶的資料共有100位元組。這就表明:本報文段的資料的第一個位元組的序號是301,最後一個位元組的序號是400。顯然,下一個報文段(如果還有的話)的資料序號應當從401開始,即下一個報文段的序號欄位值應為401。這個欄位的名稱也叫做“報文段序號"
(4)確認號:

佔4位元組、是期望收到對方下一個報文段的第一個資料位元組的序號。例如,B正確收到了A傳送過來的一個報文段,其序號欄位值是501,而資料長度是200位元組 (序號501~700),這表明B正確收到了A傳送的到序號700為止的資料。因此,B期望收到A的下一個資料序號是701,於是B在傳送給A的確認報文段中把確認號置為701。請注意,現在的確認號不是501,也不是700,而是701總之,應當記住若確認號=N,則表明:到序號N-1為止的所有資料都已正確收到。由於序號欄位有32位長,可對4GB(即4千兆位元組)的資料進行編號。在一般情況下可保證當序號重複使用時,舊序號的資料早已通過網路到達終點了
(5)資料偏移:佔4位、它指出TCP報文段的資料起始處距離TCP報文段的起始處有多遠。這個欄位實際上是指出TCP報文段的首部長度。由於首部中還有長度不確定的選項欄位,因此資料偏移欄位是必要的。但應注意,“資料偏移”的單位是32位(即以4位元組長的字為計算單位,不足4位元組需要補齊)。由於4位二進位制數能夠表示的最大十進位制數字是15,因此資料偏移的最大值是60位元組(15×4位元組),這也是TCP首部的最大長度(即選項長度不能超過40位元組)。
(6)保留:
佔6位,保留為今後使用,但目前應置為0。

六個控制位:
(7)緊急URG(Urgent):佔一位、當URG=1時,表明緊急指標欄位有效。它告訴系統此報文段中有緊急資料,應儘快傳送(相當於高優先順序的資料),而不要按原來的排隊順序來傳送。例如,已經發送了很長的一個程式要在遠地的主機上執行。但後來發現了一些問題,需要取消該程式的執行。因此使用者從鍵盤發出中斷命令( Contr+C)。如果不使用緊急資料,那麼這兩個字元將儲存在接收TCP的快取末尾。只有在所有的資料被處理完畢後這兩個字元才被交付接收方的應用程序。這樣做就浪費了許多時間。當URG置1時,傳送應用程序就告訴傳送方的TCP有緊急資料要傳送。於是傳送方TCP就把緊急資料插入到本報文段資料的最前面,而在緊急資料後面的資料仍是普通資料。這時要與首部中緊急指標 (Urgent Pointer )欄位配合使用。
(8)確認ACK( Acknowledgment ):佔一位、僅當ACK=1時確認號欄位才有效。當ACK=0時確認號無效。TCP規定,在連線建立後所有傳送的報文段都必須把ACK置1。
(9)推送PSH(PuSH):佔一位、當兩個應用程序進行互動式的通訊時,有時在一端的應用程序希望在鍵入一個命令後立即就能夠收到對方的響應。在這種情況下,TCP就可以使用推送操作。這時,傳送方TCP把PSH置1,並立即建立一個報文段傳送出去。接收方TCP收到PSH=1的報文段,就儘快地(即“推送”向前)交付接收應用程序,而不再等到整個快取都填滿了後再向上交付。雖然應用程式可以選擇推送操作,但推送操作很少使用。
(10)復位RST( Reset ):佔一位、當RST=1時,表明TCP連線中出現嚴重差錯(如由於主機崩潰或其他原因),必須釋放連線,然後再重新建立運輸連線。RST置1還用來拒絕一個非法的報文段或拒絕開啟一個連線。RST也可稱為重建位或重置位。
(11)同步SYN( Synchronization ):佔一位、在連線建立時用來同步序號。當SYN=1而ACK=0時,表明這是一個連線請求報文段。對方若同意建立連線,則應在響應的報文段中使SYN=1和ACK=1。因此,SYN置為1就表示這是一個連線請求或連線接受報文。
(12)終止FIN(FINis):佔一位、用來釋放一個連線。當FN=1時,表明此報文段的傳送方的資料已傳送完畢,並要求釋放運輸連線。

(13)視窗:佔2位元組、視窗值是[0,2^16-1]之間的整數。視窗指的是傳送本報文段的一方的接收視窗(而不是自己的傳送視窗)。視窗值告訴對方:從本報文段首部中的確認號算起,接收方目前允許對方傳送的資料量(以位元組為單位)。之所以要有這個限制,是因為接收方的資料快取空間是有限的。總之,視窗值作為接收方讓傳送方設定其傳送視窗的依據。
(14)檢驗和:佔2位元組、檢驗和欄位檢驗的範圍包括首部和資料這兩部分。和UDP使用者資料報一樣,在計算檢驗和時,要在TCP報文段的前面加上12位元組的偽首部。偽首部的格式與UDP使用者資料報的偽首部一樣。但應把偽首部第4個欄位中的17改為6(TCP的協議號),把第5欄位中的UDP長度改為TCP長度。接收方收到此報文段後,仍要加上這個偽首部來計算檢驗和。若使用IPv6,則相應的偽首部也要改變。
(15)緊急指標:佔2位元組、緊急指標僅在URG=1時才有意義,它指出本報文段中的緊急資料的位元組數(緊急資料結束後就是普通資料)。因此,緊急指標指出了緊急資料的末尾在報文段中的位置。當所有緊急資料都處理完時,TCP就告訴應用程式恢復到正常操作。值得注意的是,即使視窗為零時也可傳送緊急資料。
(16)選項:長度可變、最長可達40位元組。當沒有使用“選項“時,TCP的首部長度是20位元組。TCP最初只規定了一種選項(最大報文段 MSS),隨著網際網路的發展,又陸續加了幾個選項,如視窗擴大選項,時間戳選項參考[RFC 7323],選擇確認(SACK)選項參考[RFC 2018]。

資料包分析

對照報文格式看資料包

TCP的一些特性:

可靠傳輸的實現

滑動視窗

        TCP的滑動視窗都是以位元組為單位
        傳送視窗後沿的變化情況有兩種可能,1.不動--沒有收到新的確認,2.前移--收到了新的確認,但是傳送視窗不會向後移,因為不能撤銷收到的確認。如圖,B的接收視窗32號,33號報文已經到達,但是31號報文沒有到,所以接收視窗不能前移。A的傳送視窗31-41號報文都已傳送出去但是一個都沒有確認收到,所以接收視窗也不能前移。
        描述一個傳送視窗需要三個指標:P1,P2,P3,三個指標有以下的意義:
小於P1的是已傳送並已收到確認的部分
大於P3的是不允許傳送的部分
P3-P1=A的傳送視窗
P2-P1=已傳送尚未收到確認的位元組數
P3-P2=允許傳送但當前尚未傳送的位元組數(又稱為可用視窗或有效視窗)

超時重傳

        TCP採用了一種自適應演算法,它記錄一個報文段發出的時間,以及收到相應的確認的時間。這兩個時間之差就是報文段的往返時間RTT。TCP保留了RTT的一個加權平均往返時間RTTs(這又稱為平滑的往返時間,S表示 Smoothed 。因為進行的是加權平均,因此得出的結果更加平滑)。每當第一次測量到RTT樣本時,RTTs值就取為所測量到的RT樣本值。但以後每測量到一個新的RT樣本,就按下式重新計算一次RTTs:
新的RTTs=(1 - α)×(舊的RTTs)+α×(新的RTT樣本)
        在上式中,0≤α<1。若α很接近於零,表示新的RTTs值和舊的RTTs值相比變化不大,而對新的RTT樣本影響不大(RTT值更新較慢)。若選擇α接近於1,則表示新的RTTs值受新的RTT樣本的影響較大(RTT值更新較快)。已成為建議標準的RFC6298推薦的α值為1/8,即0.125。用這種方法得出的加權平均往返時間RTTs就比測量出的RTT值更加平滑。
超時重傳時間:RTO=RTTs+4×RTTd
新的RTTd=(1-β)×(舊的RTTd)+β×|RTTs-新的RTTd樣本|,這裡β推薦值為0.25

        現在還有一個問題:傳送出一個報文段,設定的重傳時間到了,還沒有收到確認。於是重傳報文段。經過了一段時間後,收到了確認報文段。現在的問題是:如何判定此確認報文段是對先發送的報文段的確認,還是對後來重傳的報文段的確認?由於重傳的報文段和原來的報文段完全一樣,因此源主機在收到確認後,就無法做出正確的判斷,而正確的判斷對確定加權平均RTTs的值關係很大。
若收到的確認是對重傳報文段的確認,但卻被源主機當成是對原來的報文段的確認,則這樣計算出的RTT和超時重傳時間RTO就會偏大。若後面再發送的報文段又是經過重傳後才收到確認報文段,則按此方法得出的超時重傳時間RTO就越來越長。
同樣,若收到的確認是對原來的報文段的確認,但被當成是對重傳報文段的確認,則由此計算出的RTTs和RTO都會偏小。這就必然導致報文段過多地重傳。這樣就有可能使RTO越來越短。
        根據以上所述,Karn提出了一個演算法:在計算加權平均RTTS時,只要報文段重傳了,就不採用其往返時間樣本。這樣得出的加權平均RTTS和RTO就較準確。
        但是,這又引起新的問題。設想出現這樣的情況:報文段的時延突然增大了很多。因此在原來得出的重傳時間內,不會收到確認報文段。於是就重傳報文段。但根據Kam演算法,不考慮重傳的報文段的往返時間樣本。這樣,超時重傳時間就無法更新。
        因此要對Karn演算法進行修正。方法是:報文段每重傳一次,就把超時重傳時間RTO增大一些。典型的做法是取新的重傳時間為舊的重傳時間的2倍。當不再發生報文段的重傳時,才根據上面給出RTO=RTTs+4×RTTd計算超時重傳時間。實踐證明,這種策略較為合理。
        總之,Kam演算法能夠使運輸層區分開有效的和無效的往返時間樣本,從而改進了往返時間的估測,使計算結果更加合理。

選擇確認
        接收方收到了和前面的位元組流不連續的兩個位元組塊。如果這些位元組的序號都在接收視窗之內,那麼接收方就先收下這些資料,但要把這些資訊準確地告訴傳送方,使傳送方不要再重複傳送這些已收到的資料。

 

        TCP的首部沒有哪個欄位能夠提供記錄位元組塊的邊界資訊。RFC2018規定,如果要使用選擇確認SACK,那麼在建立TCP連線時,就要在TCP首部的選項中加上“允許SACK”的選項,而雙方必須都事先商定好。如果使用選擇確認,那麼原來首部中的“確認號欄位”的用法仍然不變。只是以後在TCP報文段的首部中都增加了SACK選項,以便報告收到的不連續的位元組塊的邊界。由於首部選項的長度最多隻有40位元組,而指明一個邊界就要用掉4位元組(因為序號有32位,需要使用4個位元組表示),因此在選項中最多隻能指明4個位元組塊的邊界資訊。這是因為4個位元組塊共有8個邊界,因而需要用32個位元組來描述。另外還需要兩個位元組。一個位元組用來指明是SACK選項,另一個位元組是指明這個選項要佔用多少位元組。如果要報告五個位元組塊的邊界資訊,那麼至少需要42個位元組。這就超過了選項長度的40位元組的上限。網際網路建議標準RFC2018還對報告這些邊界資訊的格式都做出了非常明確的規定,這裡不再贅述。

流量控制

        所謂流量控制,就是讓傳送方的傳送速率不要太快,要讓接收方來的及接收。

滑動視窗實現流量控制:

TCP傳輸效率:

        例如,互動式使用者使用一條 TELNET 連線(運輸層為TCP協議)。假設使用者只發1個字元,加上20位元組的首部後,得到21位元組長的TCP報文段。再加上20位元組的衛首部,形成41位元組長的IP資料報。在接收方TCP立即發出確認,構成的資料報是40位元組長(假定沒有資料傳送)。若使用者要求遠地主機回送這一字元,則又要發回41位元組長的I資料報和40位元組長的確認IP資料報。這樣,使用者僅發1個字元時,線路上就需傳送總長度為162位元組共4個報文段。當線路頻寬並不富裕時,這種傳送方法的效率的確不高。因此應適當推遲發回確認報文,並儘量使用捎帶確認的方法。
        在TCP的實現中廣泛使用Nage演算法。演算法如下:若傳送應用程序把要傳送的資料逐個位元組地送到TCP的傳送快取,則傳送方就把第一個資料位元組先發送出去,把後面到達的資料位元組都快取起來。當傳送方收到對第一個資料字元的確認後,再把傳送快取中的所有資料組裝成報文段傳送出去,同時繼續對隨後到達的資料進行快取。只有在收到對前一個報文段的確認後才繼續傳送下一個報文段。當資料到達較快而網路速率較慢時,用這樣的方法可明顯地減少所用的網路頻寬。 Nagle 演算法還規定,當到達的資料已達到傳送視窗大小的半或已達到報文段的最大長度時,就立即傳送一個報文段。這樣做,就可以有效地提高網路的吞吐量。
        另一個問題叫做糊塗視窗綜合徵[RFC 813],有時也會使TCP的效能變壞。設想一種情況:TCP接收方的快取已滿,而互動式的應用程序一次只從接收快取中讀取1個位元組,然後向傳送方傳送確認,並把視窗設定為1個位元組。接著,傳送方又發來1個位元組的資料。接收方發回確認,仍然將視窗設定為1個位元組。這樣進行下去,使網路的效率很低。
        要解決這個問題,可以讓接收方等待一段時間,使得或者接收快取已有足夠空間容納個最長的報文段,或者等到接收快取已有一半空閒的空間。只要出現這兩種情況之一,接收方就發出確認報文,並向傳送方通知當前的視窗大小。此外,傳送方也不要傳送太小的報文段,而是把資料積累成足夠大的報文段,或達到接收方快取的空間的一半大小。
上述兩種方法可配合使用。使得在傳送方不傳送很小的報文段的同時,接收方也不要在快取剛剛有了一點小的空間就急忙把這個很小的視窗大小資訊通知給傳送方

擁塞控制

原因:對資源的需求>可用資源
四種擁塞控制的演算法:慢開始、擁塞避免、快重傳、快恢復
慢開始:當主機開始傳送資料的時候,先探測一下,即由小到大逐漸增大發送視窗(即由小到大增大擁塞視窗的值)。初始cwnd=1,傳送方只要順利收到一個對新報文段的確認,其擁塞視窗cwnd就立即加一。
避免擁塞:達到ssthresh值時,擁塞視窗開始從指數增長切換為線性增長。
快重傳:傳送方只要一收到3個重複確認報文,證明出現報文丟失(但不是因為網路擁塞造成的報文丟失),立即進行重傳,這樣就不會出項超時,傳送方也就不會誤認為網路出現擁塞。
快恢復:傳送方一連收到3個重複確認報文,知道只是丟失了個別報文,將門限值調整為ssthresh=cwnd/8

        首先,慢開始cwnd=1,然後指數增加cwnd,到ssthresh設定的閾值,啟動擁塞避免演算法,開始線性增長,當cwnd=24時,網路法生擁塞,cwnd降為1啟動慢開始演算法,同時調整ssthresh=24/2=12,然後指數增加cwnd,到ssthresh設定的閾值12,啟動擁塞避免演算法,開始線性增長,當cwnd=16時,傳送方一連收到三個確認報文,執行快重傳和快恢復演算法,調整ssthresh=cwnd/2=8,執行擁塞避免演算法。

主動佇列管理AQM

所謂“主動”佇列管理就是不要等路由器佇列長度已經達到最大數值時才不得不丟棄後面到達的分組,這樣就太被動了,(隨即早期丟棄)RED演算法可以實現主動佇列管理,具體實現:需要路由器維持兩個引數,即佇列最小門限和最大門限。當一個分組到達時,RED就按照規定演算法計算當前平均佇列長度。
(1)若平均佇列長度小於最小門限,則把新到達的分組放入佇列進行排隊。
(2)若平均佇列長度超過最大門限,則把新到達的分組丟棄。
(3)若平均佇列長度在最小門限和最大門限之間,則按照某一丟棄概率p把新到達的分組丟棄(這就體現了丟棄分組的隨機性)
這樣一來,使網路中隨機的一些TCP連線先啟動慢開始,就可以避免網路中一股腦的超時,然後又一股腦的慢開始,造成網路週期性的出現擁塞。當都進行慢開始時,路由器又處於空閒狀態浪費路由器處理資源,當速度都提升上來,網路肯定又會出現擁塞。執行RED演算法,可以讓網路流量得到均衡。

運輸連線管理

        TCP是面向連線的協議。運輸連線是用來傳送TCP報文的。TCP運輸連線的建立和釋放是每一次面向連線的通訊中必不可少的過程。因此,運輸連線就有三個階段,即:連線建立、資料傳送和連線釋放。運輸連線的管理就是使運輸連線的建立和釋放都能正常地進行。
在TCP連線建立過程中要解決以下三個問題
(1)要使每一方能夠確知對方的存在。
(2)要允許雙方協商一些引數(如最大視窗值、是否使用視窗擴大選項和時間戳選項以及服務質量等)
(3)能夠對運輸實體資源(如快取大小、連線表中的專案等)進行分配。
        TCP連線的建立採用客戶伺服器方式。主動發起連線建立的應用程序叫做客戶( client ),而被動等待連線建立的應用程序叫做伺服器( server )

TCP連線建立與釋放

https://blog.csdn.net/qq_42196196/article/details/81042376