让TCP容忍丢包
声明: 本文所描述的方案未经验证, 只是单纯的个人想法而已 :)
网络上看到一个问题: 如何提升高丢包率环境的 TCP 传输性能
第一反应是, 既然已经高丢包环境了, 就不要再奢求太多, 毕竟 TCP 所有的”降速”, “重传”等手段都是为了报文能”完整”抵达终点.
除非, TCP 愿意付出一些代价, 比如放宽一些条件: 比如忍受部分报文能被丢弃…
在完美主义者眼中, 可能已经指着鼻子骂了: 允许丢弃, 这还是 TCP 吗 ?!
这确实违背了 TCP 的”可靠传输”的原则。不过,这并不妨碍其具有一定的工程意义.
整体思路是:
- 发送端应用程序设置报文携带的内容可以被丢失.
- 接收端分析收到的报文, 当出现丢包时,接收窗口会出现 Gap,如果后续收到的报文指示这个 Gap 的内容是可忍受被丢失,则视为这段 Gap 的报文已经被接收,向发送端反馈推进窗口的 ack。
为了实现这个思路,我们需要发送端报文的 TCP option 携带更多的信息.
这里新设计了一个 TCP 选项, 选项内容包含2个值:
- lastSeq 表示最近一段可以丢失的报文的起始序号
- lastLength 表示最近一段可以丢失的报文的长度
+-----------------------------+-----------------+------------------+-----------------+
| Kind = last-tolerate-range | length = 8 | lastSeq | lastLength |
+-----------------------------+-----------------+------------------+-----------------+
举个栗子,发送端发送若干长度为 500 Bytes 或者 1000 Bytes。其中长度为 500 的报文我们认为是重要的 (必须送达),而长度为 1000 的报文则是可以忍受丢失的。
注意 last-tolerate-range指示的范围是可以合并的(长度可能超过 1000),并且不可丢失的报文也会携带该选项。
接收端收到报文后,需要解析 last-tolerate-range 选项。
我们知道当发生丢包时, 接收端会先收到序号更靠后的报文,此时缓冲区形成 gap。接收端此时根据 last-tolerate-range 指示的范围与 gap 的重叠情况,可以进行不同的处理
情形一: 完全覆盖
此时, last-tolerate-range指示的范围完全覆盖了Gap. 此时接收端可以用 0x00 (用其他也可以, 我随便举个例子) 完全填充 Gap,
这段数据被视为已经完全收到,然后向发送端回复 ACK,请求序号3001 之后的报文。
情形二: 部分覆盖
此时, last-tolerate-range指示的范围部分覆盖了Gap。此时接收端同样会将last-tolerate-range指示的范围用 0x00填充,再根据它是否紧跟 Gap 的左边沿回复不同的ACK。两种情况下,应答的序号都为必须送达但还未收到数据的最小序号。
情形三: 完全不覆盖
此时,last-tolerate-range指示的范围完全没有覆盖Gap。此时接收端的处理与普通TCP一致,它会发送ACK请求Gap左边沿序号的数据。
好了,这样一来,我们就把是否可以丢失的权利完全交给应用程序,如果应用程序坚持一个字节都不能丢,那么最终表现的行为就和 TCP 别无二致。反之,如果应用要传输的报文是有区别的,比如对一些音视频直播应用来说,播放流畅更重要,中间的一些数据丢就丢了,这个协议就有用了。