TCP的那些事兒(2)

2021-09-30 13:31:31 字數 2779 閱讀 4390

tcp要保證所有的資料報都到達,就必須要採取重傳機制,注意:接收端給傳送端的ack只能確定最大連續的包,比如,傳送端傳送了1,2,3,4,5個資料報,但是接收端只收到了1,2,所以ack = 3,然後收到了4(這時候3還沒有收到),此時的tcp會怎麼辦呢?正如前面所說的,sequence number都是以位元組數為單位的,所以ack的時候不能跳著確認,只能確認最大的連續收到的包,不然傳送端就認為之前的都收到了。

一種是不回ack死等3,當傳送方收不到對方的ack超時後,會重傳3,一旦接收方收到了3,會ack4,表示3和4都收到了,但是這種方式有個嚴重的問題就是如果一味的死等3,這樣4和5也相當於處於死等狀態,所以這個時候如果4和5先收到了,那麼傳送方也完全不知道發生了什麼。而且有可能會導致4和5的重傳。

對此,有兩種選擇:

1.僅僅重傳timeout的包,上面的資料報3.

2.重傳timeout包後的所有資料報,也就是要重傳3,4,5這三個資料報。

這兩種方式各有優劣,第一種方式會節省寬頻,但是慢;第二種方式會浪費寬頻,也可能存在一些無用功,單數速度稍微快一點,但總體來說都不好,因為要等待timeout,這個timeout我們並不能具體確定,可能會很長。

於是,tcp引入了一種叫做fast retransmit的方法,這種方法不以時間驅動,而是以資料驅動,如果傳送方的資料報沒有連續到達,就ack那個可能丟失了的包,如果連續三次的ack都是這個資料,就重傳。

fast retransmit的好處是不用等timeout了再重傳。

比如:如果傳送方傳送了1,2,3,4,5五份資料報,第乙份接收方接收到了ack2,由於某些原因2沒有收到,過了一會3收到了,還是ack2,一會4,5也受到了還是ack2,三次ack = 2以後,傳送端知道2沒有收到,於是就重發2,這一次資料報2收到了,由於3,4,5都已經收到了,於是ack6。可以參照下圖:

fast retransmit只解決了乙個問題,就是timeout的問題,但是是僅僅重發ack的資料報,還是重發所有的資料報這個問題依然沒有解決,因為2沒有收到,3,4,5收到了之後ack2,傳送端根本不知道這三個連續的ack是誰發回來的,也許傳送端發了20個資料,而ack是10,16,20傳回來的呢,測可能導致重傳從2到20的所有資料報(這就是某些tcp實際的實現),所以快速重傳機制是一把雙刃劍。

另外一種更好的方式:(selective acknowledgment (sack))這需要再tcp頭裡面加乙個sack的東西,ack還是fast retransmit的ack,sack則是匯報收到的資料碎版。示意圖:

這樣,傳送端就可以根據sack的資料知道那些資料到了,那些資料還沒有到,所以這是對快速重傳機制的一種優化,當然,這個協議需要兩邊都支援,在linux下,可以設定tcp_sack這個引數帶開這個功能。(linux2.4以後預設開啟)。

這裡還要注意乙個問題就是接收端reneging,所謂reneging就是接收端有權把已經報給傳送端的sack裡的資料丟掉,這樣乾是不被鼓勵的,這個事會把問題複雜化,但是,接收方這麼做可能會存在極端情況,比如,接收端要把記憶體給更重要的東西,所以傳送方也不能完全依賴sack,還是要依賴ack,還要維護timeout,如果後續ack的值始終沒有增長,就把sack的東西重傳,另外置收端永遠不能把sack的包標記為ack。

注意:sack消耗傳送方的資源,如果攻擊者給資料傳送方一堆sack的選項,這可能導致傳送方要重傳甚至遍歷已經發出去的所有資料,這會消耗很多傳送方的資源。

又叫做d_sack,其主要用sack來告訴傳送方那些資料重**送了,d_sack用sack第一段來做標記。

1.如果sack的第一段被ack的範圍所覆蓋,這種情況叫做d_sack.

2.如果sack的第一段的範圍被sack第二段的範圍覆蓋,這種情況叫做d_sack。

示例一:

ack丟包

由上面的圖可以看出來,丟了兩個ack所以傳送端重傳了第一段(3000-3499)於是第三行接收端發現重複收到,所以回了sack = 3000 - 3500,因為第三行ack = 4000,意味著收到了4000之前的所有資料,所以這個sack就是d_sack.主要告訴傳送端接收端收到了重複的資料,而且這樣傳送端還知道資料吧並沒有丟,是ack丟了。

網路延時

如上圖所示:網路包(1000-1499)被延誤了,經過下面三次ack觸發了fast retransmit,導致傳送端重傳(1000-1499),但是後面原來1000-1499的包又

傳過來了,所以回了乙個sack = 1000-1500,但是ack已經到了3000所以這個是d_sack。

可見,引入d_sack有下面幾點好處:

1.可以讓傳送方知道,到底是資料報丟了,還是ack包丟了。

2,是不是自己的timeout太小了,導致重傳。

3,網路上出現了先發的包後到的情況(

reordering)。

4,網路上是不是把我的資料報複製了。

知道這些東西可以很好的幫助tcp了解網路情況,從而很好的做網路上的流控。

這個功能可以通過設定linux下的tcp_dsack引數開啟(linux2.4以後預設開啟)。

TCP的那些事兒

傳送方 client 接收方 server tcp三次握手是建立連線的過程。第一次握手 client問server 你在嗎?第二次握手 server回應client 我在!第三次握手 client告訴server 東西給你!為什麼三次握手就夠了?第一次握手如果成功,server就知道自己可以收到cl...

TCP和UDP的那些事兒

下面我們將根據這些問題,做一些簡單的解釋 應用 同樣的我們來解剖一下tcp看一下它的首部 可靠性保證 你可能會有這樣的疑問,握手為什麼非得三次,如果說因為tcp是全雙工的,需要雙方先自報家門,兩次完全就夠了,為什麼最後還要再經過客戶端的一次確認,這不是多餘的嗎?這樣的疑問不是沒有道理,我們先來看乙個...

object的那些事兒

昨天和大姐qq。說給我看了,今年找到物件。我就在那裡騙他們。說我找了乙個 人。明年去 以後就沒有多少機會見到他們了。呵呵,大姐就說這樣我不聽話,那樣不聽話,不讓我去,說還借我錢買房子,不能去,去了父母白養這麼大了,我總是騙他們,逗他們。以前還騙他們說我出家。有一段時間,工作不順心,我壓力挺大的。不知...