咱們以前介紹SACK選項的時候說過,SACK能夠把接收端系列號空間的洞反映給發送端,所以發送端能夠更充分的理解接收端的狀況,而進行更好的重傳恢復過程。這種過程有時候也叫作advanced loss recovery。linux
1、數據接收端SACK行爲緩存
咱們經過一個wireshark示例來講明接收端的SACK行爲:tcp
如上圖,爲了方便在info列中查看SACK信息,我把info列中TSopt的信息隱藏了,同時把源地址列和目的地址列一塊兒隱藏了。client依次發送P1(1-6)、P2(25-30)、P3(13-18)、P4(37-42)、P5(49-54)、P6(7-12)、P7(31-36)、P8(19-24)、P9(43-48)其中括號中的數字爲相對系列號,接收端SACK行爲簡述以下(詳細的能夠參考原始的wireshark文件)ide
接收端在接收到P1後回覆的No5確認包中不包含SACK信息測試
在接收到P2後回覆的No7確認包中包含的SACK塊爲(25-31)this
接收端在接收到P3後回覆No9確認包,包含的SACK塊爲(13-19),(25-31)spa
接收端在接收到P4後回覆No11確認包,包含的SACK信息爲(37-43),(13-19),(25-31)3d
接收端在接收到P5後回覆No13確認包,包含的SACK信息爲(49-55),(37-43),(13-19),上圖截圖中對應的SACK信息就是這個確認包的信息server
接收端在接收到P6後回覆No15確認包,包含的SACK信息爲(49-55),(37-43),(25-31)blog
接收端在接收到P7後回覆No17確認包,包含的SACK信息爲(25-43),(49-55)
接收端在接收到P8後回覆No19確認包,包含的SACK信息爲(49-55)
接收端在接收到P9後回覆No21確認包,接收端系列號空間中再也不存在洞,由於這個確認包中再也不包含SACK信息。
上面的每一個ACK確認包都會包含一個TSopt的選項,從上面第5點能夠看到,在ACK確認包包含有TSopt選項的時候,最後只能包含3個SACK塊,此時TCP頭長已經到達60bytes的最大值不能在容納更多的SACK塊了。
另外注意就是SACK塊是按照最新造成的洞信息倒序排列的。每一個ACK報文中能夠攜帶多個SACK塊的緣由是由於ACK確認包有可能會丟包,可是ACK報文不消耗系列號所以不會進行重傳,所以接收端經過多個ACK報文中冗餘的SACK塊信息來提升SACK信息傳輸的可靠性。
2、數據發送端SACK行爲
TCP鏈接要利用SACK信息還須要發送端根據接收到的SACK信息執行選擇性重傳(selective retransmisson或者叫作selective repeat)。首先根據SACK信息來填充洞,而後在傳遞新數據(RFC6675),可是具體實現上可能會有一些差別。另外按照RFC2018,當TCP初始化一個RTO超時重傳的時候須要清空SACK信息,可是RFC6675認爲RTO超時保留SACK信息也是有必定必要性的。RFC2018還要求發送端只有收到TCP頭中的累計ack number的時候才能釋放對應的發送緩存,而不能根據SACK信息釋放,緣由是接收端有可能先發送一個SACK塊,而後後面又不在反饋這個SACK塊(SACK reneging)。(實際上按照協議發送端接收到的SACK塊多是接收端已經丟棄的TCP報文,雖然這個報文丟棄了可是特定狀況下接收端仍然能夠在SACK塊中攜帶這個報文信息,而在實現上若是linux內存不足,那麼有可能會丟掉已經收到的亂序TCP報文)。SACK reneging的示例咱們後面會在FACK介紹中進行簡單介紹。
另一個須要注意的就是在快速重傳的時候dup ACK的定義,RFC6675中對於SACK下dup ACK的定義以下
For the purposes of this specification, we define a "duplicate acknowledgment" as a segment that arrives carrying a SACK block that identifies previously unacknowledged and un-SACKed octets between HighACK and HighData. Note that an ACK which carries new SACK data is counted as a duplicate acknowledgment under this definition even if it carries new data, changes the advertised window, or moves the cumulative acknowledgment point, which is different from the definition of duplicate acknowledgment in [RFC5681].
其中
"HighACK" is the sequence number of the highest byte of data that has been cumulatively ACKed at a given point. "HighData" is the highest sequence number transmitted at a given point.
下面咱們仍是重點關注一下Linux實現上的處理吧。
3、SACK下的重傳示例
一、SACK打開可是不攜帶SACK選項的場景
前面咱們介紹快速重傳示例的時候,都是把tcp_sack開關設置爲0。其中有一個示例以下
其中No12-No14三個數據包是不帶有SACK選項的ACK確認包。能夠看到server在接收到三個dup ack後觸發了快速重傳,咱們設置tcp_sack爲1後從新運行測試程序,抓包以下,能夠看到server在接收到三個不帶有SACK選項的dup ack後並無觸發快速重傳,由此能夠看到SACK下對於dup ACK理解上的差別。
二、帶有SACK選項的快速重傳
下面咱們看一個帶有SACK的快速重傳,下面的測試程序與上面相似,一樣打開tcp_sack功能,不一樣的時候此次在No12確認包中包含17-25的SACK塊信息,在No13確認包中包含17-33的SACK塊信息,在No14確認包中包含17-41的SACK塊信息。No12-No14確認包的ack number都是9,在收到No14確認包後累計收到三個dup ACK,所以觸發了快速重傳。注意這裏對dup ACK的認定並非由於ack number相同,而是由於SACK塊中累計反饋了三個發送出去的數據包。
三、SACK下ack number不一樣的dup ACK
上面咱們說過SACK下對於dup ACK的認定並非由於ack number不一樣。咱們在來看一個例子,從下圖能夠看到wireshark顯示兩個dup ack後就觸發了快速重傳,其實是由於wireshark對於dup ack的認定只關注ack number致使的。在No11中帶有17-25的SACK塊信息,No12中帶有17-33的SACK塊信息,No13中帶有17-41的SACK塊信息。按照上面SACK下對於dup ACK的定義,server實際上已經接收到了3個dup ACK,所以觸發了快速重傳。