詳解TCP:順序和丟包問題


  為了保證順序性,每一個包都有一個 ID。在建立連接的時候,會商定起始的 ID 是什么,然后按照 ID 一個個發送。假設A發給B的數據流由一個500 000字節的文件組成,MSS為1000字節。數據流的首字節ID為0,那么TCP會將這個文件分為500個報文段,每一個報文段的首部序號字段中分別為0、1000、2000...

 如果第二個報文段先於第一個到B,也就是包的順序出錯。TCP RFC中並沒有詳細描述對這種問題的處理,一般是工程師自己來解決。一般有兩種方案:1)B立即丟棄失序報文段 2)B保留這個報文段,並等待缺少的字節來填補該間隔,第二種是常用的方法。

  為了保證不丟包,對於發送的包都要進行應答。具體是怎么實現的呢?比如發一個確認一個,很明顯這樣效率太低。TCP采用的是累計確認,例如確認號是5,代表5之前序號的包都收到了。A首部中的確認號是期望從B收到的下一個字節的序號。為了記錄所有發送的包和就收的包,TCP發送端和接收端都用緩存來保存這些記錄。發送端的緩存里是按照包的 ID 一個個排列根據處理的情況分成四個部分:

  • 發送了並且已經確認的
  • 發送了並且尚未確認的
  • 沒有發送,但是已經等待發送的
  • 沒有發送,並且暫時還不會發送的

為什么沒有發送的要分為兩種呢?這里就涉及到流量控制了。流量控制是一個 速度匹配服務,即發送方的發送速率與接收方應用程序的讀取速率相匹配。 在 TCP 里,接收端會給發送端報一個窗口的大小,叫Advertised window。這個窗口的大小應該等於上面的2、3之和,就是已經交代了沒做完的加上馬上要交代的。超過這個窗口大小的,接收端做不過來,就不能發送了。發送端的數據結構如下:

對於接收端來講,它的緩存里記錄的內容要簡單一些。第一部分:接受並且確認過的;第二部分:還沒接收,但是馬上就能接收的;第三部分:還沒接收,也沒法接收的。對應的數據結構為:

LastByteRead 之后是已經接收了,但是還沒被應用層讀取的;NextByteExpected 是第一部分和第二部分的分界線;MaxRcvBuffer:'大緩存的量;以上面的圖為例,在發送端來看,1、2、3 已經發送並確認;4、5、6、7、8、9 都是發送了還沒確認; 10、11、12 是還沒發出的;13、14、15 是接收方沒有空間,不准備發的。 在接收端來看,1、2、3、4、5 是已經完成 ACK,但是沒讀取的;6、7 是等待接收的;8、9 是已經接收,但是沒有 ACK 的。

  發送端和接收端當前的狀態為:

  • 1、2、3 沒有問題,雙方達成了一致。
  • 4、5 接收方說 ACK 了,但是發送方還沒收到,有可能丟了,有可能在路上。
  • 6、7、8、9 肯定都發了,但是 8、9 已經到了,但是 6、7 沒到,出現了亂序,緩存着但是沒辦法 ACK。

假設 4 的確認到了,不幸的是,5 的 ACK 丟了,6、7 的數據包丟了,這該怎么辦呢?一種方法就是超時重試,即對每一個已經發送了但是沒有 ACK 的包,都有設一個定時器,超過了一定時間,就重發。但是這個超時的時間如何評估呢?這個時間不宜過短,時間必須大於包的往返時間 RTT,否則會引起不必要的重傳。也不宜過長,這樣超時時間變長,訪問就變慢了。如果過一段時間,5、6、7 都超時了,就會重新發送。接收方發現 5 原來接收過,於是丟棄 5;6 收到了,發送 ACK,要求下一個是 7,7 不幸又丟了。當 7 再次超時又需要重傳的時候,TCP 的策略是超時間隔加倍。每當遇到一次超時重傳的時候,都會將下一次超時時間間隔設為先前值的兩倍。兩次超時,就說明網絡環境差,不宜頻繁反復發送。

  超時觸發重傳存在的問題是,超時周期可能相對較長。那是不是可以有更快的方式呢?就是快重傳機制當接收方收到一個序號大於下一個所期望的報文段時,就檢測到了數據流中的一個間格,於是發送三個冗余的 ACK,客戶端收到后,就在定時器過期之前,重傳丟失的報文段。例如,接收方發現 6、8、9 都已經接收了,就是 7 沒來,那肯定是丟了,於是發送三個 6 的 ACK,要 求下一個是 7。客戶端收到 3 個,就會發現 7 的確又丟了,不等超時,馬上重發,這樣明顯縮短了超時周期。快重傳在擁塞控制中也會用到,如何使用的細節在下一篇文章中講解。還有一種方式稱為Selective Acknowledgment (SACK)。這種方式需要在 TCP 頭里加一個 SACK 的 東西,可以將緩存的地圖發送給發送方。例如可以發送 ACK6、SACK8、SACK9,有了地圖,發送方一下子就能看出來是 7 丟了。

 

參考資料:《趣談網絡協議》劉超

     《計算機網絡:自頂向下方法》原書第六版 陳鳴譯


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM