如果第二個報文段先於第一個到B,也就是包的順序出錯。TCP RFC中並沒有詳細描述對這種問題的處理,一般是工程師自己來解決。一般有兩種方案:1)B立即丟棄失序報文段 2)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。
如果過一段時間,5、6、7 都超時了,就會重新發送。接收方發現 5 原來接收過,於是丟棄 5;6 收到了,發送 ACK,要求下一個是 7,7 不幸又丟了。當 7 再次超時又需要重傳的時候,TCP 的策略是超時間隔加倍。每當遇到一次超時重傳的時候,都會將下一次超時時間間隔設為先前值的兩倍。兩次超時,就說明網絡環境差,不宜頻繁反復發送。
參考資料:《趣談網絡協議》劉超
《計算機網絡:自頂向下方法》原書第六版 陳鳴譯