一、TCP滑動窗口
TCP雖然是面向字節(jié)流的,但是TCP傳輸的單元確實報文段。一個TCP報文段分為首部和數據部分。TCP首部前20個字節(jié)是固定的,后面有4N個字節(jié)是可選的。因此,TCP首部最小字節(jié)數是20個字節(jié)。
下面我們看下一TCP首部中幾個重要的字段:
- 源端口 和 目的端口 各占兩個字節(jié)
- 序號,占4個字節(jié)。序號范圍是[0,2^32-1],可以對4GB數據進行編號,到達最大值后,序號會重新從0開始。該序號指的是本報文段所發(fā)送數據的第一個字節(jié)的序號。
- 確認號,占4個字節(jié)。期望收到對方數據報的第一個數據字節(jié)的序號。舉例:假設B收到了A的一個報文,其序列號字段是301,數據長度是200字節(jié),這表示B正確的收到了A發(fā)送的500序號為止的所有數據。因此,B期望收到的下一個數據的序號是501,于是B把在回復A的確認報文中的確認字段設置為501。
- 確認ACK。當ACK字段為1時,確認號字段才有效。TCP規(guī)定,在連接建立后,傳輸的所有報文段的ACK都必須置1。
- 同步SYN。在連接建立時用來同步序列,也就是三次握手的時候會用到。SYN=1,ACK=0,表示這是一個連接請求報文。若對方同一連接,則回復SYN=1,ACK=1。
- 終止FIN。當FIN=1時,表示發(fā)送方數據已發(fā)送完畢,要求釋放連接(四次揮手)。
- 窗口,表示自己的接收窗口的大小。占兩個字節(jié),最大[0,2^32-1],也就是64K。
- 選項。長度可變,最大40個字節(jié)。當沒有使用選項是TCP,首部20占個字節(jié)。
1.1 什么是MSS?為什么要有MSS?
最大報文長度MSS(Maxium Segment Size),是每一個TCP報文段中數據字段的最大長度。而一個完整的 TCP報文段 = 數據字段 + 首部長度。
為什么要有MSS?因為TCP數據至少要添加20個字節(jié)的TCP首部和20個字節(jié)的IP首部,才能發(fā)送。所以,當發(fā)送的數據量少,如一個字節(jié)。那么網絡的利用率就極低。如果數據太大,會在IP層進行分片。到接收端后還要重組。如果不幸,有數據丟失或者出錯,還需要重新發(fā)送,導致開銷增大。
1.2 隨著因特網的發(fā)展,又陸續(xù)增加了幾個選項
窗口擴大選項:互聯網早期,窗口大小兩個字節(jié),最大64K夠用。為了滿足發(fā)展需要,新增窗口擴大選項,占3個字節(jié)。其中有一個字節(jié)表示表示移位值S。新的窗口大小位數從16位增加到(16+S),S最大14,故窗口最大值增加到[0,2^30-1].
時間戳選項:占10個字節(jié)。其中主要時間戳字段和時間戳回送回答字段各占4字節(jié)。作用:(1)計算RTT;(2)用于處理序號超過2^32的情況。
選擇確認選項:適用于,收到的報文段無差錯,只是未按序號,中間還缺少某些序號的數據。選擇確認就可以只讓發(fā)送方發(fā)送這些缺少的數據,后面還會詳細介紹。
二、TCP滑動窗口
Tcp的滑動窗口是以字節(jié)為單位的。
2.1 滑動窗口收發(fā)數據流程舉例
現在假設發(fā)送方A收到了接收方B的確認報文,其中確認字段是31(表示31之前的數據都已收到,需要A從31開始發(fā)數據),窗口大小是20。A會根據這兩個數據構造出自己的發(fā)送窗口,如下:
發(fā)送窗口:在沒有收到B的確認情況下,A可以連續(xù)把窗口內的數據都發(fā)出去。發(fā)送窗口內的序號都是允許發(fā)送的序號。
現假設A又發(fā)送了31~41的數據,如下圖:B此時的接受窗口如下:
此時,B雖然收到了32、33的分組,但是沒有按序接收,所以B給出的確認只能還是31。
再假設,B按序接收到了31、32、33。B把接收窗口往后往前移動3個序號,同時給A發(fā)出確認報文,窗口值仍為20,但是確認號為34。A在收到確認報文后,將自己的發(fā)送窗口也往前移動3個序號,注意,B還收到了37 38 40三個分組的數據,但是沒有按照順序,所以先暫存在自己的接收窗口。 如下:
2.2 選擇確認SACK原理
假設接收方收到若干不連續(xù)的報文段。序號1~ 1000收到了,但1000 ~ 1500沒收到。序號1501~ 3000收到了,但30001~ 3500沒收到。序號3501~4500又收到了。如果這些序號都在接受窗口內,接受方先收下這些數據,并把這些消息告訴發(fā)送方,讓發(fā)送方不在發(fā)送重復數據。我們可以看到,每個字節(jié)塊都有左右兩個邊界,我們只需要告訴發(fā)送方這些邊界信息,讓其從指定序號開始傳就達到我們的預期了。
但是,TCP首部沒有哪個字段是來描述這些信息的。選擇確認選項就派上用場了。如果要使用選擇確認,就需要在TCP首部加上允許SACK選項。由于首部選項的長度只有40個字節(jié),每個邊界需要4個字節(jié),所以,最多只能傳遞8個邊界。為什么不是5個字節(jié)塊(10個邊界信息)呢?因為這40個字節(jié),還要分出來兩個字節(jié),一個用來開啟SACK;一個字節(jié)用來指出SACK選項占幾個字節(jié)。
三、TCP流量控制
所謂流量控制就是控制發(fā)送方的發(fā)送速率,不要太快,讓接收方來得及接收處理。利用滑動窗口就可以很方便的在TCP連接上實現對發(fā)送方的流量控制。
- 接收方每次收到數據后,在發(fā)送確認的報文的時候,同時告訴發(fā)送方自己的接收窗口的大??;
- 發(fā)送方收到確認報文之后,就會調整自己的發(fā)送速率,也就是自己的發(fā)送窗口大小。當發(fā)送方收到win=0時,就會停止發(fā)送數據,同時開啟一個定時器,每隔一段時間發(fā)送探測報文詢問接收方是否有空間接受數據,如果收到win>0就發(fā)送數據;如果win=0,您先忙,我待會再來問問…
四、擁塞控制
擁塞控制就是防止過多的數據注入網絡,導致網絡過載。注意與流量控制的區(qū)別,流量控制一般是點對點的控制。而擁塞控制是一個全局性的過程,涉及所有的主機和路由器等待。
擁塞控制方法:
4.1 慢開始、擁塞避免
發(fā)送方維持一個擁塞窗口cwnd(congestion window)的狀態(tài)變量。取決于網絡擁塞程度,動態(tài)變化。發(fā)送發(fā)控制cwnd的原則:只要網絡沒出現擁塞就增大cwnd,出現了就減小。
4.1.1 發(fā)送方如何判斷網絡擁塞
當網絡出現擁塞時,路由器就要丟棄分組。因此,如果發(fā)送方沒有按時收到應該到達的確認報文,就認為網絡出現擁塞。
4.1.2 算法原理
為方便描述,我們用報文個數作為窗口大小的單位,實際上單位是字節(jié)。慢開始的思路就是,剛開始將cwnd設置為一個MSS的數值,每經過一個傳輸輪次cwnd就加倍。
傳輸輪次:擁塞窗口所允許的發(fā)送的報文都連續(xù)發(fā)出去,且收到了對已發(fā)送的最后一個字節(jié)的確認。
因為是加倍(指數)增長,為了防止增長過度引起網絡阻塞,還設置一個慢開始門限ssthresh。當cwnd超過ssthresh時,就改為擁塞避免算法,也就是線性緩慢增長。
無論是在慢開始還是擁塞避免階段,只要發(fā)送方判斷網絡出現擁塞,就會把ssthresh設置為擁塞時發(fā)送窗口的一半,cwnd設置為1,重新執(zhí)行慢開始算法。
4.2 快重傳和快恢復
快重傳算法要求接收方每收到一個失序的報文段,就立即發(fā)出重復確認,目的是使發(fā)送方及早知道有報文段丟失。如果發(fā)送方連續(xù)手動三次重復的確認就立即重傳對方未收到的報文。
因為可以收到連續(xù)三個重復報文的確認,發(fā)送方不認為是網絡出現了擁塞。使用快恢復算法。快恢復思路是:把cwnd設置為ssthresh的一半,然后開始擁塞避免算法。
在采用快重傳算法時,慢開始算法只在TCP建立連接和網絡出現超時的時候使用。
上面的描述都是假定接收方總是有足夠的空間接受數據。實際上接收方的空間也是有限的,接收方根據自己的接受能力設置接受窗口rwnd。因此:
發(fā)送方窗口 = MIN[rwnd, cwnd]文章來源:http://www.zghlxwxcb.cn/news/detail-432420.html
文章參考于<零聲教育>的C/C++linux服務期高級架構文章來源地址http://www.zghlxwxcb.cn/news/detail-432420.html
到了這里,關于TCP滑動窗口、流量控制及擁塞控制詳解的文章就介紹完了。如果您還想了解更多內容,請在右上角搜索TOY模板網以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網!