tcp如果收到ack後,不管是順序ack還是重複ack(可能帶有sack選項),都可能對傳輸佇列進行4次掃瞄,它們先後順序分別是:
故事發生在tcp_ack->tcp_sacktag_write_queue函式
故事發生在
tcp_ack->
tcp_sacktag_write_queue->函式主體
故事發生在
tcp_ack->
tcp_sacktag_write_queue->
tcp_mark_lost_retrans
故事發生在
tcp_ack->
tcp_sacktag_write_queue->if (...) tcp_update_reordering
整個故事如下圖所示:
如果una向前推進了,我們就不多說了,如果沒有推進una,而且有sack標記(請注意,fack並不是一種特殊的模式,它只是sack的一種激進重傳方案)的情況下,第一遍掃瞄會完成上述的1.1,1.2,1.3這三件事,其中第一件事就不說了,就是按照ack資料報的選項,將傳輸佇列中的被選項選中的資料報標記為sack;第二件事有點複雜,一般而言,tcp的每一種重傳機制除了rto的退避機制會重傳多次之外,只會將資料報重傳一次,但是事實上並不絕對,如果可以啟發到重傳的資料報有很高的概率丟失,那麼就可以將該重傳過的資料報抹去其「已重傳」標誌,這意味著如果有哪個執行路徑認為其可以被重傳,那麼它將會被再次重傳一次!
如何判斷乙個重傳的資料報已經丟失呢?請看linux協議棧之tcp_mark_lost_retrans函式,其主要思想是:
在重傳每乙個資料報的時候,記錄重傳當時的snd_nxt,記為其ack_seq欄位,如果發現乙個被重傳的資料報的ack_seq後面的資料報都被sack了,那麼就說明該重傳資料報可能又一次沒有到達接收端,丟失了!注意,這也是一種啟發式演算法,因為在重傳資料報n的時候,其ack_seq幾乎同時也被傳輸了,那麼正常來講,它們的ack應該同時到來,然而資料報n的ack_seq後面的都被sack了,而資料報n卻沒有被sack,說明它可能丟失了。如下圖所示:
關於1.3,請看《
tcp擁塞控制**(不包括rto,因為它太簡單了)》 原圖中的網路重排序一節。
需要說明的是,對於1.3而言,掃瞄的時候,總是找到fack(請注意,它僅僅是乙個計數器而已)最左邊的第乙個資料報(fack計數器每次都要從左到右擼一遍,擼的同時,記錄從左到右第乙個遇到的被sack的資料報【它可能是被sack的,也可能是被dsack的】),然後fack與該資料報之間的距離就是新的reordering的值(如果它比老的reordering大的話)。
故事發生在tcp_ack->tcp_clean_rtx_queue
完成第一遍掃瞄之後,緊接著進行的第二遍掃瞄會根據新的una值,清除掉其左邊直到prior una之間的資料報,同時,更重要的是,更新各個計數器,需要更新的計數器有,包括但不限於:
第二遍掃面的宗旨有二,其一是向前推進una,清除傳送佇列的skb,其二就是更新tcp的計數器,標準化「在途流量」。
故事發生在tcp_ack->
tcp_fastretrans_alert->
tcp_update_scoreboard
首先第一遍掃瞄標記了sacked了哪些資料,並且清除了大概率已經丟失的重傳資料標記,第二遍掃瞄清除了已經被順序ack的資料,那麼現在該第三遍掃瞄了,即標記出哪些是已經丟失的資料,這個標記演算法是啟發式的,並不能表明一定準確,所以linux的實現專門提供了各種undo機制!具體的細節,還是參見《
tcp擁塞控制**(不包括rto,因為它太簡單了)》
故事發生在tcp_ack->
tcp_fastretrans_alert->tcp_xmit_retransmit_queue
哪些資料報被sack(已經標記),哪些被ack(已經清除),哪些被當成lost(已經標記),接下來該做什麼呢?很顯然,該重傳了!到底怎麼重傳呢?還是參見《
tcp擁塞控制**(不包括rto,因為它太簡單了)》以及其開頭展示的勘誤。
本文用很短的篇幅簡述了linux協議棧收到tcp的ack包後的反應,開啟了4遍掃瞄(對於fast路徑,沒有第一遍!),每一遍掃瞄都完成很少的特定任務,最終完成tcp的快速重傳。
故事還沒有結束
TCP之ACK傳送場景
我現在的理解,在有以下幾種情景,tcp會把ack包發出去 1.收到1個包,啟動200ms定時器,等到200ms的定時器到點了 第二個包沒來 於是對這個包的確認ack被傳送。這叫做 延遲傳送 2.收到1個包,啟動200ms定時器,200ms定時器還沒到,第二個資料報又來了 兩個資料報乙個ack 3.收...
TCP服務端傳送資料(C )
本文記錄c 實現tcp協議的服務端部分,注意文中的阻塞態會長期存在,知道客戶端響應為止。include pch.h include include pragma comment lib,ws2 32.lib using namespace std intmain int argc,char ar 建...
監聽tcp客戶端傳送資料
因近期專案對接機械人,且機械人對接僅支援tcp協議 component public class springlistener implements commandlinerunner client.close server.close catch exception e 執行緒處理類 class ...