【概述】
TCP 是在 IP 的不可靠服务的基础上建立的一种可靠数据传输服务
其提供的可靠传输服务,就是要保证接收方进程从缓冲区读出的字节流与发送方发出的字节流是完全一致的
与链路层的可靠性传输机制相似,TCP 中的可靠传输使用了校验、序号、确认、重传等机制来完成这个目的
由于 TCP 的校验与 UDP 的校验几乎一致,只是将伪首部的协议字段由 $6$ 改为了 $17$,这里不再赘述
【序号】
TCP 协议是面向字节数据流的,其将数据看作一个无结构但有序的字节流,通过 TCP 数据报的序号字段来保证数据能有序提交给应用层
TCP 连接中,传送的数据流的每一个字节都会编上一个序号,序号字段的值是本 TCP 报文段发送的数据的第一个字节的序号
如下图所示,一 TCP 报文段的序号字段值为 $301$,携带的数据共有 $100B$,这就表明本报文段的数据的最后一字节的序号为 $400$,下一报文段的数据序号应从 开始 $401$ 开始
【确认】
TCP 首部的确认号是期望收到对方的下一报文段的数据的第一个字节的序号
TCP 默认使用累计确认方式,即若确认号为 $N$,则表明到序号 $N-1$ 为止的所有数据都已被正确接收
例如,B
正确收到了 A
发送的一个报文段,其序号字段为 $501$,数据长度为 $200B$,这表明 B
正确收到了 A
发送的到序号 $700$ 为止的数据,因此,B
期望收到 A
的下一数据序号为 $701$,于是 B
发送给 A
的确认号会置为 $701$
【重传】
在传输层中,有两种事件会导致对 TCP 报文段的重传:超时、冗余 ACK
超时
超时机制
与链路层类似,TCP 每发送一个报文段,就会对这个报文段设置一个计时器,只要计时器设置的重传时间到期,但还没有收到这一确认,就重传这一报文段
由于 TCP 的下层是一个互联网环境,因此 IP 数据报所选择的路由变化很大,这导致了传输层的往返时延的方差也很大
为计算超时计时器的重传时间,TCP 采用了一种自适应的算法
加权平均往返时间
一个报文段发出的时间、收到相应确认的时间的差被称为报文段的往返时间(Round-Trip Time,RTT)
TCP 保留了 RTT 的一个加权平均往返时间 $RTT_s$,当第一次测量 RTT 样本时,$RTT_s$ 值为测量到的 RTT 样本值,以后每次测量到一个新的 RTT 样本 $RTT_n$,就按照下式来重新计算一次 $RTT_s$
其中,$0\leq \alpha \leq1$,若 $\alpha$ 接近于 $0$,说明 RTT 值更新较慢,新的 $RTT_s$ 与旧的 $RTT_s$ 变化不大,受新测量的 $RTT_n$ 影响较小;若 $\alpha$ 接近于 $1$,说明 RTT 值更新很快,新的 $RTT_s$ 与旧的 $RTT_S$ 变化较大,受新测量的 $RTT_n$ 影响较大
RTF 2988 中,推荐 $\alpha=0.125$
超时重传时间
超时计时器设置的超时重传时间(Retransmission Time-out,RTO)应该略大于上面得出的加权平均往返时间 $RTT_S$,其采用下式进行计算:
其中,$RTT_D$ 是 RTT 的偏差的加权平均值,其与 $RTT_s$ 和 $RTT_n$ 的差有关
在第一次测量时,$RTT_D$ 为测量到的新 RTT 样本值 $RTT_n$ 的一半,之后的每次测量中,采用下式计算:
其中,$0\leq \beta \leq 1$,推荐 $\beta=0.25$
冗余 ACK
超时触发重传存在的一个问题,就是超时周期太长,但发送方通常可在超时时间发生前,通过冗余 ACK 来检测丢包情况
在 TCP 中,规定每当期望序号大的失序报文段到达时,发送冗余 ACK,指明下一个期待字节的序号
同时,当发送方收到同一个报文段的 $3$ 个冗余 ACK 时,可以认定这个确认报文段后的报文段已经丢失,此时,可以立刻对这个丢失的报文段进行重传,这被称为快速重传
举例来说,发送方 A
发送了序号为 $1,2,3,4,5$ 的报文段,其中 $2$ 号报文段在链路中丢失,将无法到达接收方 B
由于 $3,4,5$ 号报文段对 B
来说就成了失序报文段,B
会发送 $3$ 个对 $1$ 号报文段的冗余 ACK,表示自己希望接收 $2$ 号报文段
而 A
收到了 $3$ 个对 $1$ 号报文段的 ACK,就认为 $2$ 号报文段已经丢失,可以立即对 $2$ 号报文段进行重传