TCP-IP詳解:SACK選項(Selective Acknowledgment)

參考教材:TCP-IP Guide


引入理由

在文章TCP-IP詳解:超時重傳機制中,有介紹到快速重傳和超時重傳都會面臨到一個重傳什麼包的問題,因爲發送端也不清楚丟失包後面傳送的數據是否有成功的送到。主要原因還是對於TCP的確認系統,不是特別的好處理這種不連續確認的狀況了,只有低於ACK number的片段都被收到纔有進行ACK,out-of-order的片段只能是等待,同時,這個時間窗口是無法向右移動的。

舉個例子:

1. 服務發送4個片段給客戶端,seg1(seq=1,len=80),seg2(seq=81,len=120), seg3(seq=201,len=160),seg4(seq=361,len=140)

2. 服務器收到seg1和seg2的ACK = 201,所以此時seg1 seg2變成發送並已經確認範疇的數據包,被移除滑動窗口,此時服務器又可以多發80+120 byte數據

3. 假設seg3由於某些原因丟失,這個時候服務器仍然可以像客戶端發送數據,但是服務器會等待seg3的ACK,否則窗口無法滑動,卡主了

4. seg3丟失了,即使後面的seg4收到了,客戶端也無法告知服務器已經收到了seg4,試想一下,如果窗口也夠大,服務器可以繼續持續發送更多的片段,那麼這些片段被客戶端接收,只能存放到隊列中,無法進行確認

正式因爲後續OUT-OF-ORDER的報文段的發送狀況也不清楚,所以Server也不是特別清楚要如何去處理這種狀況,不過一般來說只能有2中狀況:

1. 只重傳超時的數據包,這種方法是最常想到的,比較實用與後面的數據包都能夠正常接收的狀況,只重傳超時的數據包,但是如果比較壞的情況下,丟失了很多封包呢?  那就需要一個一個的等待超時了,很浪費時間。

2. 重傳這個片段以及之後的所有包,這種方法在最壞的狀況下,看起來效率還是挺高的,但是如果只有一個包丟失,就去重傳後面所有接受到的包,流量浪費也是很嚴重的。

總之對於上面闡述的問題,沒有想到一個好的思路來解。但是RFC2018提供了一個SACK的方法,有效的解決這個問題


SACK(Selective Acknowledgment)

SACK是一個TCP的選項,來允許TCP單獨確認非連續的片段,用於告知真正丟失的包,只重傳丟失的片段。要使用SACK,2個設備必須同時支持SACK纔可以,建立連接的時候需要使用SACK Permitted的option,如果允許,後續的傳輸過程中TCP segment中的可以攜帶SACK option,這個option內容包含一系列的非連續的沒有確認的數據的seq range,這些

SYN包中SACK Permitted 選項,雙方都支持纔對

SACK option格式

Kind 5  Length  剩下的都是沒有確認的segment的range了 比如說segment 501-600 沒有被確認,那麼Left Edge of 1st Block = 501,Right Edge of 1st Block = 600,TCP的選項不能超過40個字節,所以邊界不能超過4組


可以看下實際的tcpdump抓包中的SACK option,如下圖,使用tcp.option.sack進行過濾,可以看到這個SACK option只有一個片段,接收並沒有進行確認,範圍是18761~20101


再來將上面的例子

客戶端收到seg4的時候,發送seg3的ACK 會產生一個SACK的option(361~500),Server收到這個ACK後,就知道seg3丟失了,但是seg4已經收到了但是並沒有確認,所以就只會重傳seg3


SACK的產生,RFC2018

SACK通常是由數據接收方產生,如果在connection建立的時候,SYN包中有SACK-Permitted 的選項爲true,同時自身也支持SACK,那麼可以在接收異常的時候,產生SACK option. 如果要發送,SACK中需要攜帶接收隊列中所有沒有被確認的數據段信息。

如果接收方選擇發送帶有SACK的ACK,需要遵循如下規則:

1. 第一個block需要指出是哪一個segment觸發SACK option ,我認爲就是誰亂序了,纔會導致SACK

2. 儘可能多的把所有的block填滿

3. SACK 要報告最近接收的不連續的數據塊

接收端的行爲:

1. 數據沒有被確認前,都會保持在滑動窗口內

2. 每一個數據包都有一個SACKed的標誌,對於已經標示的segment,重新發送的時候會忽略

3. 如果SACK丟失,超時重傳之後,重置所有數據包SACKed 標誌


D-SACK RFC2883

D-SACK主要是使用了SACK來告訴發送方有哪些數據被重複接收了,如果是D-SACK,那麼SACK option的第一個block代表被重複發送的序列片段

需要注意的點:

1. D-SACK僅僅是接收端報告一個重複的連續的片段

2. 每個重複的連續片段只能在一個block中

3.  重複片段的序列號

4. 第二個block指的是data沒有被確認的

分析一下RFC2883的例子:

1. Reproting a Duplicate Segment

如下圖: 發送端發送seg1和seg2,但是接收端的ACK都被drop掉了,超時重傳seg1,然後接收端就發了一個D-SACK,告訴發送端3000~3499重複接收,需要接收4000的。


2. 報告OUT-OF-ORDER段和重傳段

從圖中可以看出seg4 out-of-order會觸發SACK,說明已經收到但是沒有確認的數據,但是這個丟掉了,通過發送方又重傳了seg1,然後接收方此時會生成D-SACK,block1中存放了dup的segment,block2中存放了收到但沒有確認的segment


還有比較多的例子,詳細的可以參考 RFC2883

總起來說D-SACK還是帶了諸多的好處,能否讓發送方瞭解是ACK丟了還是發送的數據包丟了,重複發送就說明是ACK丟了唄,同時也能夠掌握網絡上的一些事情,比如out-of-order,超時重傳等,這樣瞭解了網絡,才能更好的做流控。



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