計算機網絡--傳輸層

用戶數據報協議UDP(User Datagram protocol)是無連接的,僅最大可能交付,沒有擁塞控制,面向報文(對於應用傳下來的報文不合並也不拆分,只添加UDP首部),支持一對一,一對多,多對一,多對多的交互通信。

傳輸控制協議TCP(Transmission Control protocol)是面向連接的,提供可靠交付,有擁塞控制,流量監控,通過雙工通信,面向字節流(把應用層傳下來的看成字節流,把字節流組織成大小不等的數據塊),每一條TCP連接只能是點對點的(一對一)。

UDP首部格式:

首部字段只有8個字節,包括源端口、目的端口、長度、檢驗和。12字節的僞首部是爲了計算校驗和臨時添加的。

TCP首部格式

序號:對於字節流進行編號,例如序號爲301,表示第一個字節的標號爲301,如果攜帶的數據長度爲100字節,那麼下一個報文段的序號爲401.

確定號:期望收到的下一個報文的序號,例如B正確收到A發送來的一個報文段,序號爲501,攜帶的數據長度爲200字節,因此B期望下一個報文段的序號爲701,B發送給A的確認報文段中的確認好爲701.

數據偏移:指的是數據部分距離報文段起始的偏移量,實際上指的是首部長度。

確認ACK:當ACK=1時確認號確認號字段有效,否則無效。TCP規定,在連接建立後所傳送的報文必須把ACK置1。

同步SYN:在連接建立時用來同步序號。當SYN=1,ACK=0時表示這是一個連接請求報文段。若對方同意建立連接,則響應報文中SYN=1,ACK=1.

終止FIN:用來釋放一個連接,當FIN=1,ACK=0時表示這是一個連接請求報文段,若對方同意建立連接,則響應報文中SYN=1,ACK=1

窗口:窗口作爲接受方讓發送方設置其發送窗口的依據。之所以要有這個限制,是因爲接收方的數據緩存空間是有限的。

TCP如何保證可靠傳輸

  • 校驗和:TCP將保證他首部和數據的校驗和。這是一個端到端的校驗和,目的是檢測數據在傳輸過程中的任何變化。如果收到段的校驗和有差錯,TCP將丟棄這個報文段和不確認收到此報文段
  • 流量控制:TCP連接的每一方都有固定大小的緩衝空間,TCP的接收端只允許發送端發送接收端緩衝區能接納的數據。當接收方來不及處理髮送方的數據,能提示發送方降低發送的速率,防止包丟失。TCP使用的流量控制協議是可變大可變小的滑動窗口協議。(TCP利用滑動窗口來進行流量控制)。
  • 擁塞控制:當網絡擁塞時,減少數據的發送(慢開始、擁塞避免、快重傳、快恢復)。
  • 停止等待協議:也是爲了實現可靠傳輸的,它的基本原理就是每發完一個分組就停止發送,等待對方確認。在收到確認後在發下一個分組。超時重傳:當TCP發出一個段後,他啓動一個定時器,等待目的端確認收到這個報文段。如果不能及時收到一個確認,將重發這個報文段。

TCP的三次握手:

左邊爲客戶端,右邊爲服務端:

  • 首先服務端處於監聽狀態,等待客戶的連接請求。
  • 客戶端主動打開,向服務端發送請求連接報文,SYN=1,ACK=0,選擇一個初始的序號x(seq = x)。
  • 服務端收到連接請求報文,如果同意建立連接,則向客戶端發送連接確認報文,SYN=1,ACK=1,確認號爲x+1,同時也選擇一個出事的序號y(seq=y)。
  • 客戶端收到服務端的連接確認報文後,還要向服務端發出確認,確認號爲y+1,序號爲x+1。
  • 服務端收到客戶端的確認後,連接建立。

三次握手的原因:

第三次握手是爲了防止失效的連接請求到達服務器,讓服務器錯誤打開連接。

客戶端發送的連接請求如果在網絡中滯留,那麼就會隔很長一段時間才能收到服務器端發回的連接確認。客戶端等待一個超時重傳時間後,就會重新請求連接。但是這個滯留的連接請求最後還是會到達服務器,如果不進行三次握手,那麼服務器就會打開兩個連接。如果有三次握手,客戶端會忽略服務器之後發送的對滯留連接請求的連接確認,不會進行三次握手,因此就不會在打開連接。

TCP的四次揮手:

左邊爲客戶端,右邊爲服務端:(注:發起斷開的可以是客戶端,也可以是服務端)

  • 第一次揮手,客戶端發送連接釋放報文,FIN=1.客戶端進入FIN_WAIT_1狀態,表示客戶端沒有數據再會發送給服務端(TCP屬於於半關閉狀態)。
  • 第二次揮手,服務端接收到客戶端發送到的FIN報文段(進入CLOSE_WAIT狀態),發出確認(ACK,seq),此時服務端還能向客戶端發送數據。客戶端進入TIME_WAIT_2狀態。
  • 第三次揮手,當服務端不再需要連接時,服務端向客戶端發送連接釋放報文,FIN=1。同時服務端進入LAST-ACK狀態。
  • 第四次揮手,客戶端收到發出的確認返回ACK,進入TIME-WAIT狀態,等待2MSL(報文最大存活時間)後如果沒有收到回覆,則證明服務端已經正常關閉,則釋放連接。服務端收到客戶端的確認後釋放連接。

四次揮手的原因:

客戶端發送了FIN連接釋放報文之後,服務器收到了這個報文,就進入CLOSE_WAIT狀態。這個狀態是爲了讓服務器端發送還爲傳送完畢的數據,傳送完畢之後,服務器會發送FIN連接釋放報文。

四次揮手狀態變化的解釋:

  • FIN_WAIT_1:FIN_WAIT_1和FIN_WAIT_2狀態的真正含義都是表示等待對方的FIN報文。而這兩種狀態的區別是:FIN_WAIT_1的狀態實際上是當socket在ESTABLISHED狀態時,他想主動關閉連接,向對方發送FIN報文,此時該socket即將進入FIN_WAIT_1狀態。而當對方迴應ACK報文後,則進入FIN_WAIT_2狀態,當然在實際的正常情況下,無論對方何種狀態,都會馬上回應ACK報文,所以FIN_WAIT_1狀態比較難遇到,而FIN_WAIT_2狀態常常可以用netstat(可以列出系統上所有的網絡套接字連接情況)看到。(主動方)
  • FIN_WAIT_2:在FIN_WAIT_2狀態下的socket,表示半連接,也即有一方要求close連接,但另外還告訴另一方,在等等還有數據需要發送。(主動方)
  • CLOSE_WAIT:當收到對方的FIN報文後,系統回覆ACK報文給對方,此時進入CLOSE_WAIT狀態。接下來考慮的是,被動方是否還有數據需要傳送,如果沒有傳送的話就可以關閉這個socket,發送FIN給對方,即關閉連接,所以在CLOSE_WAIT狀態下需要完成的事情是等待去關閉連接。(被動方)
  • LAST_ACK:是被動關閉一方再發送FIN後等待對方最後的ACK報文。當收到ACK報文後,也既可以進入CLOSED可用狀態。
  • TIME_WAIT:表示收到了對方的FIN報文,併發送處了ACK報文,就等2MSL後即可回到CLOSED可用狀態。如果FINWAIT1狀態下,收到了對方同時帶FIN標誌和ACK標誌的報文時,可直接TIME_WAIT狀態,無需FIN_WAIT_2。設置TIME_WAIT的兩個理由:
    1. 確保最後一個確認報文能夠到達。如果B沒有收到A發送來的確認報文,那麼就會重新發送連接釋放請求報文,A等待一段時間就是爲了處理這種情況的發生。
    2. 等待一端時間是爲了讓本連接持續時間內所產生的所有報文都從網絡中消失,使得下一個新的連接不會出現舊的連接請求報文。
  • CLOSED:表示連接中斷。

三次握手與四次揮手面試中常見的問題:

1.初始化連接SYN超時問題:

  • 在三次握手時,客戶端發送SYN包給服務端以後就掛了,服務端回覆SYN-ACK給服務端以後,一直沒有收到客戶端的ACK確認,這個時候連接既沒有建立起來,也不能說是失敗了。(這就需要一個超時時間來讓server將連接斷開),否則這個連接會一直佔用server的SYN連接列中的一個位置,大量這樣的連接就會將server的SYN隊列耗盡,讓正常的連接無法處理。
  • 目前linux系統中默認進行5次重發SYN-ACK包,重試的間隔時間從1s開始,下次重試間隔是前一次的雙倍,5次的時間間隔爲1s,2s,4s,8s,16s,總共31s,第5發出後還需要32s才知道第5次也超時了,所以總共要63s,由於SYN超時需要63s,那麼就給了攻擊者一個攻擊服務器的機會,攻擊者在短時間內把大量的SYN包發送給服務端(俗稱SYN flood攻擊),用於耗盡Server端的SYN隊列。
  • 什麼是SYN攻擊:(SYN攻擊指的是,攻擊客戶端在短時間內僞造大量不存在的IP地址,向服務器不斷髮送SYN包,服務器回覆確認包,並等待客戶端的確認。由於原地址不存在,服務端需要不斷地重發直至超時,這些僞造的SYN包長時間佔用未連接隊列,正常的SYN請求被丟棄,導致目標系統運行緩慢,嚴重者會引起網絡阻塞和系統癱瘓)。
  • 如何檢測SYN攻擊:
    • 檢測SYN攻擊非常方便,當你在服務器中看到大量半連接的狀態時,特別是原IP地址是隨機的,基本上就可以斷定是一次SYN攻擊。在linux上使用系統自帶的netstats命令來檢測SYN攻擊。
  • 如何防禦SYN攻擊:
    • SYN攻擊不能被完全阻止,除非TCP協議重新設計。我們所能做的是儘可能減輕SYN攻擊的危害,常見的SYN攻擊有以下幾種:
      • 縮短SYN的時間
      • 增加最大連接次數
      • 過濾網管防護(過濾網管首先要指明的防火牆,過濾網管防護首先要包羅超時設置,SYN網管和SYN署理三種)
      • SYN cookies技術

2.如果已經建立了連接,但是客戶端突然出現故障了怎麼辦?

TCP設有一個保活計時器,顯然,客戶端如果出現故障,服務端不能一直等下去,白白浪費資源。服務器每收到一次客戶端的請求後都會重新復位這個計時器,時間通常是設置爲2小時,若兩小時還沒有收到客戶端的任何數據,服務器就會發送一個探測報文段,以後每隔75分鐘發送一次。若一連發送10個探測報文仍然沒反應,服務器就認爲客戶端出了故障,接着關閉連接。

3.四次揮手時,當客戶端和服務端兩邊同時斷開時:(參考圖片)

由圖片可以看出:

TCP的客戶端在收到服務端的FIN包前發出了FIN包,那麼服務端的狀態變成了FIN_WAIT1,

客戶端在FIN_WAIT1狀態下收到了服務端的FIN的ACK包後,那麼客戶端的狀態變爲FIN_WAIT2,

客戶端在FIN_WAIT2下收到服務端的FIN包,在確認已經收到了服務端的全部數據後,就響應ACK給服務端,然後進入TIME__WAIT。

但是,因爲兩端是同時斷開的,所以如果客戶端在FIN_WAIT_1時收到了服務端的FIN包的話,客戶端發出確認信號ACK給服務端,然後進入CLOSEING狀態,客戶端在CLOSEING狀態下收到了自己的FIN包的ACK的話,那麼就進入TIME_WAIT狀態。於是TCP的兩端同時發出FIN包的進行斷開連接,那麼兩端可能出現完全一樣的狀態轉移FIN_WAIT1——>CLOSEING——>TIME_WAIT,也就時客戶端和服務端最後同時進入TIME_WAIT狀態。

4.TCP的TIME_WAIT狀態:

爲什麼主動關閉方進入TIME_WAIT,被動關閉方可以進入嗎?

如果主動關閉方不進入TIME_WAIT,那麼主動關閉方在發完ACK以後就直接關閉,如果最後發送的ACK包沒有傳送到對端時,這時被動關閉方沒有收到自己的FIN的ACK就不能關閉連接,接着被動關閉方就會超時重傳FIN包,但是這個時候已經沒有對端會給該FIN回覆ACK,被動關閉就無法正常關閉連接了。所以主動關閉方需要進入TIME_WAIT以便能夠重發丟掉的被動關閉方FIN的ACK。

TIME_WAIT狀態爲什麼需要經過2MSL的時間關閉連接?

爲了保證主動端發送的最後一個確認報文能夠到達被動端。這個確認報文可能會丟失,如果被動端收不到這個確認報文其會重傳FIN和ACK報文,而主動端會在2MSL時間內收到這個重傳的報文段,每次客戶端收到這個重傳報文後,就會重啓2MSL計時器。這樣可以保證客戶端和服務端正常關閉。

爲了防止已失效的報文段出現在下一次連接中。主動關閉方經過2MSL後,可以保證本次連接中傳輸的報文段都在網絡中消失,這樣一來就能夠保證在後面的連接中不會出現舊的連接產生的報文段了。

TIME_WAIT狀態是用來解決或避免什麼問題?

在上面提過,如果主動關閉放沒有TIME_WAIT時,就會引發一系列的問題,當主動關閉方關閉時,被動關閉方沒有收到自己的FIN會重傳FIN包到主動關閉放,由於此時連接已經不存在了,主動關閉方無法識別FIN包,協議棧會任務被動關閉當”瘋了“,都沒有建立連接就發送FIN包?於是就會回覆RST包給被動關閉方,被動關閉方就會收到一個錯誤(connect reset by peer)。

防止已經斷開的連接在鏈路中殘留的FIN包終止掉新的連接(重用了已斷開連接的所有的5元素源IP,目的IP,TCP,源端口,目的端口。這個概率比較低,涉及到了匹配問題,遲到的FIN分段的序號必須落在新連接的一方的期望序列範圍內雖然概率低,但是確實可能發生,因爲初始序列都是隨機的,並且序列號是32位,會迴繞)。

TIME_WAIT會帶來哪些問題?

TIME_WAIT帶來的問題:一個連接進入TIME_WAIT狀態後需要等待2MSL的時長才能斷開連接佔用的資源,會造成以下的問題:

作爲服務器:短時間內關閉大量的Client連接,會造成服務器出現大量TIME_WAIT連接,佔用大量的tuple,嚴重消耗服務器的資源。

最爲客戶端:短時間內大量的短連接,會大量消耗Client機器的端口,畢竟端口只有65535個,端口被耗盡了,後續就無法在發起新的連接了。

如何解決TIME_WAIT的一些問題:

修改tcp_max_tw_buckets:tcp_max_tw_buckets控制併發的TIME_WAIT的數量,默認值是180000.如果超過默認值,內核會把多的TIME_WAIT連接清掉,然後在日誌裏打一個警告。官網文檔說這個選項只是爲了阻止一些簡單的Dos攻擊,平常不要人爲的降低它。

啓動快速回收機制,對應內核中net.ipv4.tcp_tw_recycle。要搞清楚這個參數必須搞清楚net.ipv4.tcp_timestamps:

net.ipv4.tcp_timestamps是在RFC 1323中定義的一個TCP選項。
tcp_timestamps的本質是記錄數據包的發送時間
TCP作爲可靠的傳輸協議,一個重要的機制就是超時重,因此如何計算一個準確的RTO對於TCP性能有着重要的影響,而tcp_timestamp主要爲此設計的。

當timestamp和tw_recycle兩個選項同時開啓情況下,開啓per-host的PAWS機制。從而能快速回收處於TIME-WAIT狀態的TCP流。快速回收一般是70ms即可回收

開啓重用機制

5.TCP的延時確認機制:

全名Delayed Acknowledgment,簡稱延時ACK,翻譯爲延時確認,延遲ACK的目的是爲了減少網絡中傳輸大量的小報文,該報文是針對ACK報文的.一個來自發送端的報TCP會延遲ACK的發送,等待一段時間,希望應用程序會對剛剛收到的數據進行應答,這樣可以用新數據講ACK捎帶過去.(一般情況下這個時延在40ms~50ms之間,如果在這時間因爲發送方接收到消息以後,那麼ACK將隨數據一塊發送,對於這個時延需要注意的是,這個時延並不是指的收到數據發送ACK的時間延遲,而是內核會啓動一個定時器,每隔200ms就會檢查一次,比如定時器0ms啓動,200ms到期,180ms的時候數據到來,那麼20ms後沒有新的數據到來,ACK仍然會發送,這個時延爲20ms).

這樣做的目的:

  • 這樣做的目的ACK報文可以合併發送,可以降低流量.
  • 按照TCP協議確認機制是累計的,也就是說本身的確認號爲X,X指的是所有X之前的數據不包含X的數據都已經收到,所以如果收到按序的兩個包,只需要第二個確認號即可,這樣可以省下一個ACK的消耗.RFC建議最多等待兩個包的積累,這樣可以保證消息的及時通知.

6.TCP的窗口機制:

TCP協議裏窗口機制有2種:一種是固定窗口大小;一種是滑動窗口大小。

固定窗口:這個窗口的大小就是一次傳輸幾個數據,對所有數據幀按順序進行編號,發送方在發送過程中始終保持着一個發送窗口,只有落在發送窗口內的幀才允許被髮送,同時接收方也維持着一個接受窗口,只有落在接收窗口內的幀才允許接收。這樣可以調整發送方窗口和接收方窗口的大小可以實現流量控制。

如圖所示:

假設滑動窗口大小爲1,每次只能發送一個數據只有接收方對這個數據進行確認以後才能發送第二個數據。我們可以看到發送方每發送一個數據接受方就要給發送方一個ACK對這個數據進行確認。只有接收到了這個確認數據以後發送方纔能傳輸下個數據。這樣如果說窗口過小,那麼當傳輸比較大的數據的時候就需要不停的發送與確認,這個時候就會造成很大的延遲。如果說窗口的大小定義的過大。這樣可能就會造成擁塞的情況。這是固定窗口的工作原理。

滑動窗口:

滑動窗口協議是TCP使用的一種流量控制方法。該協議允許發送方在停止並等待接收確認報文前可以連續發送多個分組。由於發送方不必每發一個分組就停下來等待確認,因此該協議可以加速數據的傳輸。只有在接收窗口向前滑動時(與此同時也發送確認),發送窗口才有可能向前滑動。收發兩端的窗口按照以上規律不斷向前滑動,因此這種協議成爲滑動窗口協議。

在滑動窗口中緩存內的數據可以分成四類:

1.Sent and Acknowledged(已發送並收到確認):這些數據表示以發送成功並已經確認的數據,比如圖中的前31個bytes,這些數據其實的位置是在窗口之外,因爲窗口內順序最低的被確認之後,要移除窗口,實際上是窗口進行合攏,同時打開接收新的待發送的的數據。

2.Send But Not Yet Acknowledged(已發送但未接收到確認):這部分數據稱爲發送但沒有被確認,數據被髮送出去,沒有收到接收端的ACK,認爲並沒有完成發送,這屬於窗口內的數據。

3.Not Send,Recipient Ready to Receive(允許發送但未發送):稱爲可用窗口或有效窗口,這部分是儘快發送的數據,這部分數據已經被加載到緩存中,也就是窗口中了,等待發送,其實這個窗口時完全由接收方告知的,接受方告知還時能夠接受這些包,所以發送方需要儘快的發送這些包。

4.No Send, Recipent Not Ready to Receive:這些數據屬於未發送同時接受段也不允許發送的,因爲這些數據已經超出了發送端所接收的範圍。

對於發送方來講,窗口內包括兩部分:發送窗口(已經發送了爲收到ACK),可用窗口,接受端允許發送但是沒有發送的那部分稱爲可用窗口。

滑動窗口的原理:

  1. 假設32~45這些數據,是上層Application發送給TCP的,TCP將其分成四段發送給服務端。
  2. 1:32~34  2:35~36  3:37~41  4:42~45這四個片段,依次發送出去,此時假設接收端收到了1,2,4
  3. 此時接收端的行爲時回覆一個ACK包說明已經接收到了32~36的數據,並將4進行緩存(保證順序,產生一個保存3的hole)
  4. 發送端接收到ACK以後,就會將32~36的數據包從發送並沒有確認切到發送已確認,這個時候窗口向右移動,可用窗口增大。
  5. 對於丟失的3,如果超時一定時間,TCP就會重新傳送(重傳機制),重傳成功以後3,4一塊被確認,不成功seq4也將被丟棄。
  6. 就是不斷地重複上述的動作來進行數據的傳輸和流量的控制,原理圖如下所示。

TCP滑動窗口的剖析:

滑動窗口協議的基本原理就是在任意時刻,發送方都維持了一個連續的允許發送的幀的序號,稱爲發送窗口;同時,接收方也維持了一個連續的允許接收的幀的序號,稱爲接收窗口。發送窗口和接收窗口的序號的上下界是不一樣的,甚至大小也可能不同。不同的滑動窗口協議靠口大小一般不同。

滑動窗口的3種動作:展開(右邊向右),合攏(左邊向右),收縮(右邊向左)這三種動作受接收端的控制。

合攏:表示已經接收到相應字節的確認

展開:表示允許緩存發送更多對的字節

收縮(非常不希望出現的,一般是禁止的):表示本來可以發送的,現在不能發送了;但是如果收縮的是那些已發送的,就會有問題;爲了避免收端會等待緩存中有更多的緩存空間時才進行通信。

7.TCP的超時重傳:

每一個數據包都帶有下一個數據包的編號,如果下一個數據包沒有收到,那麼ACK的編號就不會發生變化,如果發送方發現收到三個連續 的重複ACK,或者超時了還沒有收到任何ACK,就會確認丟包,從而在發送這個包。

TCP的發送方在規定的時間內沒有收到確認就要重傳已發送的報文段。但是重傳的時間確實TCP最複雜的問題之一。由於TCP的下層是互聯網環境,發送的報文段可能只經過一個高速的局域網,也可能經過多個低速網絡,並且每一個IP數據包所選擇的路由還可能不同。如果超時重傳時間設置太短,就會引起很多報文的不必要的重傳,是網絡負荷增大。但若把超時重傳時間設置的過長,則又使得網絡的空閒時間增大,降低傳輸速率。

TCP採用了自適應算法,記錄了一個報文段發出的時間,以及收到相應的確認的時間。這兩個時間之差就是報文段的往返時間RTT。TCP保留了RTT的一個加權平均往返時間RTTs(平滑往返時間 )。每當第一次測量到RTT樣本時,RTTs值就取爲所測量到的RTT樣本值。但有以後每測量到一個新的RTT樣本,就會按下式重新計算一次RTTs。

新的RTTs = (1-\alpha )\timesRTT = ( ALPHA * SRTT ) + ((1-ALPHA) * RTT)——其中的 α 取值在0.8 到 0.9之間

RTO = min[UpBOUND,max[LowBOUND,(BETA*SRTT)]]——BETA(延遲方差因子(BETA is a delay variance factor (e.g., 1.3 to 2.0))

針對上面算法問題,有衆多大神改進,難以長篇累牘,推薦閱讀《TCP 的那些事兒》、《TCP中RTT的測量和RTO的計算

TCP的重傳機制:

  • 通過上面我們可以知道,TCP的重傳是由超時觸發的,這會引發一個重傳選擇問題,假設TCP發送端連續發了1、2、3、4、5、6、7、8、9、10共10包,其中4、6、8這3個包全丟失了,由於TCP的ACK是確認最後連續收到序號,這樣發送端只能收到3號包的ACK,這樣在TIME_OUT的時候,發送端就面臨下面兩個重傳選擇:

    僅重傳4號包

    優點:按需重傳,能夠最大程度節省帶寬。

    缺點:重傳會比較慢,因爲重傳4號包後,需要等下一個超時纔會重傳6號包

    重傳3號後面所有的包,也就是重傳4~10號包

    優點:重傳較快,數據能夠較快交付給接收端。

    缺點:重傳了很多不必要重傳的包,浪費帶寬,在出現丟包的時候,一般是網絡擁塞,大量的重傳又可能進一步加劇擁塞

  • 快速重傳算法:

    • 就是在連續收到3次相同確認號的ACK,那麼就進行重傳。這個算法基於這麼一個假設,連續收到3個相同的ACK,那麼說明當前的網絡狀況變好了,可以重傳丟失的包了。

  • 選擇確認算法(SACK):

    • 快速重傳解決了timeout的問題,但是沒解決重傳一個還是重傳多個的問題。出現難以決定是否重傳多個包問題的根源在於,發送端不知道那些非連續序號的包已經到達接收端了,但是接收端是知道的,如果接收端告訴一下發送端不就可以解決這個問題嗎?於是提出了SACK算法。

    • SACK中加入了一個SACK選項(TCP option field),允許接收端在返回Duplicate ACK時,將已經收到的數據區段(連續收到的數據範圍)返回給發送端,數據區段與數據區段之間的間隔就是接收端沒有收到的數據。發送端就知道哪些數據包已經收到,哪些該重傳,因此SACK的發送端可以在一個RTT時間內重傳多個數據包。

    • 整個TCP選項長度不超過40字節,實際最多不超過4組邊界值。

SACK依靠接收端的接收情況反饋,解決了重傳風暴問題,這樣夠了嗎?接收端能不能反饋更多的信息呢?顯然是可以的,於是,RFC2883對對SACK進行了擴展,提出了D-SACK,也就是利用第一塊SACK數據中描述重複接收的不連續數據塊的序列號參數,其他SACK數據則描述其他正常接收到的不連續數據。這樣發送方利用第一塊SACK,可以發現數據段被網絡複製、錯誤重傳、ACK丟失引起的重傳、重傳超時等異常的網絡狀況,使得發送端能更好調整自己的重傳策略。

D-SACK,有幾個優點:

發送端可以判斷出,是發包丟失了,還是接收端的ACK丟失了。(發送方,重傳了一個包,發現並沒有D-SACK那個包,那麼就是發送的數據包丟了;否則就是接收端的ACK丟了,或者是發送的包延遲到達了)

發送端可以判斷自己的RTO是不是有點小了,導致過早重傳(如果收到比較多的D-SACK就該懷疑是RTO小了)。

發送端可以判斷自己的數據包是不是被複制了。(如果明明沒有重傳該數據包,但是收到該數據包的D-SACK)

發送端可以判斷目前網絡上是不是出現了有些包被delay了,也就是出現先發的包卻後到了。

8.TCP的流量控制:

  • 利用滑動窗口看來實現流量控制。所謂流量控制就是讓發送方的發送速率不要太快,要讓接收端來得及接收。
  • 考慮一種情況:
    • TCP的每一個連接都設有一個持續計時器。當接收窗口的大小爲0時,只要TCP連接的一方收到對方的零窗口通知,就會啓動持續計時器。若持續計時器設置的時間到期,就會發送零窗口探測報文(僅攜帶一個字節的數據),而對方就在確認這個報文段時給出一個現在的窗口值。如果窗口仍未零,那麼收到報文段一方就重新設置持續計時器。如果窗口不是零,那麼死多的僵局就會打破。這樣也可以及時的確認發送的報文是否丟失。
  • 必選考慮傳輸效率:Nagle算法
    • 算法如下:若發送應用程序吧要發送的數據逐個字節地發送到TCP的發送緩存,則發送方就把第一個數據字節先發送出去,把後面到達的數據字節都緩存起來。當發送方接收到第一個數據字符的確認後,再把發送緩存中的所有數據組裝成一個報文段發送出去,同時繼續對隨後到達的數據進行緩存。只要在收到對一個報文段的確認後才繼續發送下一個報文段。當數據到達較快而網絡速率較慢時,用這樣的方法可明顯地減少所用網絡的帶寬。Nagle算法還規範ing,當到達的數據已達到發送窗口大小的一半或已達到報文段的最大長度時,就立即發送一個報文段,這樣可以有效的提高網絡的吞吐量。
    • 出現的問題(糊塗窗口綜合徵):當TCP接收的緩存已滿,而交互的應用進程一次只從TCP中讀取一個字節,然後向發送方發送確認,並把窗口設置爲1個字節。接着發送方又來1個數據。接收方發出確認,仍然將窗口設置爲1字節。這樣下去網絡的效率很低。解決辦法:讓接收方等待一段時間,使得或者接收緩存已有足夠空間容納最長的報文段,或者等到接收緩存已有一半空閒的空間。只要滿足二者之一,接收方就發出確認報文,並向發送方通知當前窗口的大小。

9.TCP的擁塞控制:

擁塞:在計算機網絡中的鏈路容量,交換節點中的緩存和處理機等,都是網絡的資源。在某一段時間,若對網絡中某一資源的需求超過了改資源所能提供的可用部分,網絡的性能就會變壞。這種情況叫做擁塞。

擁塞控制要完成的兩個任務:1:公平性,2:擁塞過後的恢復

擁塞控制算法:

  1. 慢開始算法
  2. 擁塞避免算法
  3. 快速重傳
  4. 快速恢復

慢開始算法和擁塞避免:

發送方維持一個叫做擁塞窗口cwnd的狀態變量。擁塞窗口的大小取決於網絡的擁塞程度,並且動態在變化。發送方讓自己的發送窗口等於擁塞窗口,另外考慮到接收窗口的大最終發送窗口的上限值爲Min[rwnd,cwnd].

慢開始法的思想就是,不要一開始就發送大量的數據,先探測一下網絡的擁塞程度,也就擁塞窗口的大小。

如下圖所繫慢啓動傳輸圖:

爲了防止擁塞窗口cwnd增長引起網絡擁塞,還需設置一個慢開始門限(ssthresh)。ssthresh的用法如下:

當cwnd < ssthresh 時,使用慢開始算法

當cwnd > ssthresh 時,使用擁塞避免算法

當cwnd = ssthresh時,任意使用兩種算法其中之一

擁塞避免算法讓擁塞窗口緩慢增長,即每經過一個往返時間RTT就把發送方的擁塞窗口cwnd加1,而不是加倍。這樣擁塞窗口按線性規律緩慢增長。

無論是在慢開始階段還是在擁塞避免階段,只要發送方判斷網絡出現擁塞(其根據就是沒有收到確認,雖然沒有收到確認可能是其他原因的分組丟失,但是因爲無法判定,所以都當做擁塞來處理),就把慢開始門限設置爲出現擁塞時的發送窗口大小的一半。然後把擁塞窗口設置爲1,執行慢開始算法。如下圖:

快速重傳和快速恢復:

快重傳要求接收方在收到一個失序的報文就立即重複確認,而不要等到自己發送數據時捎帶確認,快重傳算法規定,發送方只要一連收到三個重複確認就應當立即重傳對尚未收到的報文段,而不必繼續等待設置重傳計時器時間到期。如下圖:

快重傳配合使用的還有快恢復算法,有以下兩個要點:

1.當發送方連續發送三個重複確認時,就執行"乘法減小算法",把ssthresh門限減半。但是接下來並不執行慢開始算法。

2.考慮到如果網絡出現擁塞的話就不會受到重複的確認,所以發送方現在認爲網絡可能沒有擁塞。所以此時不執行慢開始算法,而是將cwnd設置爲ssthresh的大小,然後執行擁塞避免算法

如下圖:

 

 

 

 

 

 

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