丟包重發的前提是傳送方能夠知道接收方是否成功的接收了訊息。所以,在 tcp 協議中,接收端會給傳送端返回乙個通知,也叫作確認應答(ack),這表示接收方已經收到了資料報。
ack 確認
資料報和 ack 應答都有可能丟失,在這種情況下,傳送方如果在一段時間內沒有收到 ack,就會重發資料:
未收到 ack 時重發資料
即使網路連線正常,由於延遲的存在,接收方也有可能收到重複的資料報,因此接收方通過 tcp 首部中的 syn 判斷這個資料報是否曾經接收過。如果已經接收過,就會丟棄這個包。
如果傳送方等待一段時間後,還是沒有收到 ack 確認,就會啟動超時重傳。這個等待的時間被稱為重傳超時時間(rto,retransmission timeout)。rto 的值具體是多久呢?
首先,rto 的值不是固定的,它是乙個動態變化的時間。這個時間總是略大於連線往返時間(rtt,round trip time)。這個設定可以這樣理解:「資料傳送給對方,再返回到我這裡,假設需要 10 秒,那我就等待 12秒,如果超過 12 秒,那估計就是回不來了。」
rtt 是動態變化的,因為誰也不知道網路下一時刻是否擁堵。而當前的 rto 需要根據未來的 rtt 估算得出。rto 不能估算太大,否則會多等待太多時間;也不能太小,否則會因為網路突然變慢而將不該重傳的資料進行重傳。
rto 有自己的估算公式,可以保證即使 rtt 波動較大,它的變化也不會太劇烈。感興趣的讀者可以自行查閱相關資料。
按照之前的理論,在資料報發出後,直至 ack 確認返回以前,傳送端都無法傳送資料,而且包的往返時間越長,網路利用效率和通訊效能就越低。前兩張形象的解釋了這一點。
為了解決這個問題,tcp 使用了「視窗」這個概念。視窗具有大小,它表示無需等待確認應答就可以繼續傳送資料報的最大數量。比如視窗大小為 4 時,資料傳送的示意圖如下:
視窗大小為 4
不等確認就連續傳送若干個資料報會不會有問題呢?我們首先來看資料報丟失問題。
我們知道 tcp 首部中的 ack 字段表示接收方已經收到資料的最後位置。因此,接收方成功接收到了 1-1000 位元組的資料後,它會傳送乙個 ack = 1001 的確認包。假設 1001-2000 位元組的資料報丟失了,由於視窗長度比較大,傳送方會繼續傳送 2001-3000 位元組的資料報。接收端並不會返回這個資料報的確認,因為它最後收到的資料還是 1-1000 位元組的資料報。
因此,接收端返回的資料報的 ack 依然是 1001。這表示:「喂,發資料的,別往後發了,你第 1001 位元組開始的資料還沒來呢」。可以想見,傳送端以後每次傳送資料報得到的確認中,ack 的值都是 1001。當連續收到三次確認之後,傳送方會意識到:「對方還沒有接收到資料,這個包需要重傳」。
因此,引入視窗的概念後,被傳送的資料不能立刻丟棄,需要快取起來以備將來需要重發。
利用視窗傳送資料的過程可以用下圖表示:
快速重傳
如果是資料報沒有丟失,但是確認包丟失了呢?這就是視窗最擅長處理的問題了。假設傳送發收到的確認包中的 ack 第一次是 1001,第二次是 4001。那麼我們完全可以相信中間的兩個包是成功被接收的。因為如果有沒接收到的包,接收方是不會增加 ack 的。
在這種情況下,如果不使用視窗,傳送方就需要重傳第
二、三個資料報,但是有了視窗的概念後,傳送方就省略了兩次重傳。因此使用視窗實際上可以理解為「空間換時間」。
某些確認包丟失時不用重發
如果視窗過大,會導致接收方的快取區資料溢位。這時候本該被接收的資料反而丟棄了,就會導致無意義的重傳。因此,視窗大小是乙個可以改變的值,它由接收端主機控制,附加在 tcp 首部的「視窗大小」欄位中。
在連線建立的初期,如果視窗比較大,傳送方可能會突然傳送大量資料,導致網路癱瘓。因此,在通訊一開始時,tcp 會通過慢啟動演算法得出視窗的大小,對傳送資料量進行控制。
流量控制是由傳送方和接收方共同控制的。剛剛我們介紹了接收方會把自己能夠承受的最大視窗長度寫在 tcp 首部中,實際上在傳送方這裡,也存在流量控制,它叫擁塞視窗。tcp 協議中的視窗是指傳送方視窗和接收方視窗的較小值。
慢啟動過程如下:
通訊開始時,傳送方的擁塞視窗大小為 1。每收到乙個 ack 確認後,擁塞視窗翻倍。
由於指數級增長非常快,很快地,就會出現確認包超時。
此時設定乙個「慢啟動閾值」,它的值是當前擁塞視窗大小的一半。
同時將擁塞視窗大小設定為 1,重新進入慢啟動過程。
由於現在「慢啟動閾值」已經存在,當擁塞視窗大小達到閾值時,不再翻倍,而是線性增加。
隨著視窗大小不斷增加,可能收到三次重複確認應答,進入「快速重發」階段。
這時候,tcp 將「慢啟動閾值」設定為當前擁塞視窗大小的一半,再將擁塞視窗大小設定成閾值大小(也有說加 3)。
擁塞視窗又會線性增加,直至下一次出現三次重複確認應答或超時。
以上過程可以用下圖概括:
視窗大小變化示意圖
TCP 慢啟動簡介
內容絕對正確,所 以請讀者抱著懷疑的態度閱讀本部落格內的文字。如果讀 者因本部落格內的文字造成損失,本人 無力負責。如果有任何謬誤或者問題,希望讀者不吝賜教。在廣域網,tcp報文可能要經過多個路由器和速率較慢的鏈路。如果傳送方一開始就向網路 傳送多個報文段,則中間路由器的緩衝負擔會立刻加重,很可能致...
spring 啟動慢問題
在最近做spring 專案時發現工程啟動很慢,而且會卡很久,控制台輸出資訊如下 解決方法 是log4j的問題,要先啟動log4jconfiglistener,再啟動contextloaderlistener。即調整web.xml 的順序即可。如下所示 org.springframework.web....
TCP慢啟動演算法
慢啟動,是傳輸控制協議使用的一種阻塞控制機制。慢啟動也叫做指數增長期。慢啟動是指每次tcp接收視窗收到確認時都會增長。增加的大小就是已確認段的數目。這種情況一直保持到要麼沒有收到一些段,要麼視窗大小到達預先定義的閾值。如果發生丟失事件,tcp就認為這是網路阻塞,就會採取措施減輕網路擁擠。一旦發生丟失...