一、TCP的保活定时器
TCP也可以通过保护定时器来检测对端是否已经“死掉”。这和其它协议的保护机制是类似的,没什么神奇之处。二、路径MTU发现
路径MTU指的是当前在两个主机之间的路径上任何网络上的最小MTU。IP中的路径MTU发现的实现:在IP首部中设置“不要分片(DF)”比特,来发现当前路径上的路由器是否需要对正在发送的IP数据报进行分片。如果一个待转发的IP数据报被设置DF比特,而其长度又超过了MTU,那么路由器将返回ICMP不可达的差错。然后就降低数据报长度,再尝试该过程,直到找到一个可以成功到达对端的MTU,它就是路径MTU。
TCP的路径MTU发现按如下方式进行:
- 在连接建立时,TCP使用初始的MSS作为起始的报文段大小。初始的MSS为对端声明的MSS,如果对端没有指定一个MSS,则默认为536。
- 一旦选定了起始的报文段大小,在该连接上的所有被TCP发送的IP数据报都将被设置DF比特。如果某个中间路由器需要对一个设置了DF标志的数据报进行分片,它就丢弃这个数据报,并产生一个的ICMP的“不能分片”差错。
- 如果收到这个ICMP差错,TCP就减少段大小并进行重传。当由这个ICMP差错引起的重传发生时,拥塞窗口不需要变化,但要启动慢启动。
三、长肥管道
一个连接的时延带宽积可表示为:capacity(b)=bandwidth(b/s)×round-triptime(s)。也可称它为两端的管道大小。具有大的带宽时延乘积的网络被称为长肥网络(LongFatNetwork,即LFN),而一个运行在LFN上的TCP连接被称为长肥管道。使用长肥管道会遇到多种问题。
- TCP首部中窗口大小为16bit,因此窗口大小最大为65535字节,这就将发送方发送但未被确认的数据的总长度限制到了65536字节。对于LFN管道,这可能会出现所有的数据都还未到达接收方,但是发送方已受限于窗口大小而不能继续发送的情形,这就极大的降低了网络的吞吐量。扩大窗口选项可以解决这个问题。
- 根据TCP的拥塞控制,丢失分组会导致连接进行拥塞控制,即便是由于冗余ACK而进入了快速恢复,也会使得拥塞窗口降低一半,而如果是由于超时进入了慢启动,则拥塞窗口会变为1,无论是哪一种情形,发送方允许被发送的数据量都大量减小了,这会导致网络吞吐量降低。选择确认(SACK)可以用来部分避免该问题,采用该技术使得接收方可以有选择的对无序到达的报文段进行确认而不是采用累积确认,这样被确认的报文段就不会超时,也不会有冗余的ACK。
- TCP并不对每个报文段进行RTT测量。在一个长肥网络LFN上需要更好的RTT测量机制。
- TCP对每个字节数据使用一个32bit无符号的序号来进行标识。TCP定义了最大的报文段生存时间(MSL)来限制报文段在网络中的生存时间。但是在LFN网络上,由于序号空间是有限的,在已经传输了4294967296个字节以后序号会被重用。如果网络快到在不到一个MSL的时候序号就发生了回绕,网络中就会有两个具有相同序号的不同的报文段,接收方将无法区分它们的顺序。在一个千兆比特网络(1000Mb/s)中只需要34秒就可以完成4294967296个字节的发送。使用TCP的时间戳选项的PAWS(ProtectionAgainstWrappedSequencenumbers)算法(保护回绕的序号)可以解决该问题。
四、扩大窗口选项
扩大窗口选项使TCP的窗口定义从16bit增加为32bit。这是通过定义一个选项实现对16比特的扩大操作来实现的,而TCP首部的窗口大小仍为16比特。扩大窗口选项定义了一个字节的扩大因子,其取值范围为[0,14]。假设接收到了一个窗口大小为L,并且带有一个扩大因子为N的扩大窗口选项的SYN报文,则对方通告的窗口的大小为L左移N比特。
和MSS选项一样,扩大窗口因子选项只能出现在SYN报文段中,否则将被忽略。当连接建立好之后,每个数据传输方向的扩大窗口因子就固定不变了。
为了使用扩大窗口,两端必须在它们的SYN报文段中发送这个选项。主动建立连接的一方在其SYN中发送这个选项,但是被动建立连接的一方只能够在收到带有这个选项的SYN之后才可以发送这个选项。每个方向上的扩大因子可以不同。
如果主动连接的一方发送一个非零的扩大因子,但是没有从另一端收到一个扩大窗口选项,它就将发送和接收的扩大因子记为0。这就允许较新的系统能够与较旧的、不理解新选项的系统进行互操作。
可以通过修改/proc/sys/net/ipv4/tcp_window_scaling内核变量来启用或关闭扩大窗口因子选项。
HostRequirementsRFC要求TCP接受在任何报文段中的一个选项并且要求TCP忽略任何它不理解的选项。由于所有选项的长度要么是固定的,要么在kind域之后的length域,因此这是可能的。
五、时间戳选项
时间戳选项使发送方可以在每个报文段中放置一个时间戳值,然后由接收方在确认中返回这个数值,从而允许发送方为每一个收到的ACK计算RTT(因为TCP采用了累积确认,所以不是每个报文段都有自己的独立的ACK)。较大的窗口大小需要进行更好的RTT计算。RFC1323给出了需要为较大窗口进行更好的RTT计算的信号处理的理由:
通常RTT通过对一个数据信号(包含数据的报文段)以较低的频率(每个窗口一次)进行采样来进行计算。当每个窗口中有8个报文段时,采样速率为数据率的1/8,这还是可以忍受的。但是如果每个窗口中有100个报文段时,采样速率则为数据速率的1/100,这将导致被估计的RTT不精确,从而引起不必要的重传。如果一个报文段被丢失,则会使情况变得更糟。
采用时间戳选项时,发送方在第1个字段中放置一个32bit的值,接收方在应答字段中回显这个数值。
时间戳是一个单调递增的值。由于接收方只需要回显收到的内容,因此不需要关注时间戳单位是什么。这个选项不需要在两个主机之间进行任何形式的时钟同步。RFC1323推荐更新(即时间戳值加1的操作)时间戳值的频率在1毫秒和1秒之间。
该选项工作机制类似于扩大窗口选项。在连接建立阶段,主动发起连接的一方在它的SYN中指定选项。只有在它从另一方的SYN中收到了这个选项之后,该选项才会在以后的报文段中进行设置。
每个连接只维护的一个时间戳的数值,该值的维护采用如下方式:
- TCP跟踪下一个ACK中将要发送的时间戳的值(一个名为tsrecent的变量)以及最后发送的ACK中的确认序号(一个名为lastack的变量),该序号就是接收方期望的序号。
- 当一个包含有字节号lastack的报文段到达时,则该报文段中的时间戳被保存在tsrecent
- 中。
- 无论何时发送一个时间戳选项,tsrecent就作为时间戳回显应答字段被发送,而序号字段被保存在lastack中。
- 如果ACK被接收方迟延,则作为回显值的时间戳值将对应于被确认的多个报文段中的第一个报文段的时间戳,因为只有它的序号会和lastack相同。这样做是因为RTT的计算必须将对端的处理时延考虑在内,而延迟ACK实际上是处理的一部分,将它考虑在内才可以避免延迟ACK机制可能导致的不必要的重传。
- 如果具有序号lastack的报文段丢失,而其后的报文段到达,则在具有序号lastack的报文段到达时,它的时间戳(而不是在它之前到达的失序的报文段的时间戳)将被回显。这样计算将使得RTT的计算包括了冗余ACK发送的时间以及该丢失报文段重传的时间,它将具有一个较大的值,相比较小的值,较大的值不会引入不必要的重传。
1.PAWS:防止回绕的序号
时间戳选项不仅能被用于更好地计算RTT,而且利用它还可以避免将接收到的旧的报文段看做是新的数据的一部分。这就是PAWS算法。该算法思想很简单,即将时间戳看做是32比特序号的扩展,因此序号空间就被扩展到了64比特。采用该算法时,只要序号回绕的时间大于时间戳更新的时间,就可以防止将旧报文段当做新的报文段。
根据估算在一个千兆比特网络(1000Mb/s)中需要34秒可以完成4294967296个字节的发送。那么在1000M网络中发送完264字节需要,34 * 232秒。即便将网络速度增大1000 1000倍,所需的时间也很大,因此至少对目前来说,该算法已经可以很好的工作了。
当使用了该算法时,连接在TIME_WAIT等待的时间就可以不再是2MSL,而是3.5*RTO。不过需要注意的是,这里需要3.5 * RTO大于时间戳的更新间隔,否则它可能仍无法工作(如果时间戳的值还和初始化时一样时就进入了TIME_WAIT状态,它就没办法工作了)。
RTO就是重传时间间隔。3.5来自于算式:3.5 =1+2+0.5 目的是至少允许两次重传。
六、SYN cookies
在TCP的三次握手中,当执行被动打开的一端接收到执行主动打开的一端的SYN时,为了响应该请求,它会为该请求分配连接所需要的资源,然后对SYN进行确认并发送自己的SYN,如果主动打开一端不发送ACK对被动打开一端的SYN的进行确认,这些资源会被回收。攻击者可以对这种工作方式进行攻击,它可以发送执行大量的主动打开,但是又不完成TCP三次握手的第三步的动作,这就会导致执行被动打开的一端(通常是服务器)的资源被迅速耗尽而无法服务正常的请求。这种攻击被称为SYN flood攻击。
应对这种攻击的手段是 SYNcookies。
其原理是:
- 被动打开一端收到SYN时,不立即分配连接所需的资源,而是只生成一个ISN号,该ISN由一个只有自己知道的函数生成,该函数的参数至少包括了TCP socket所需的四元组的信息,可能还有一些其他私有的值。然后被动打开一端使用该ISN发送一个自己的SYN报文段,并同时对自己收到的SYN进行确认。这里的ISN被称为cookie。
- 如果主动打开一端没有对被动打开一端的SYN进行确认,由于没有实际的资源分配,因此没有什么损失
- 如果主动打开一端对被动打开一端的SYN进行了确认,则被动打开一端使用相同的函数相同的参数再计算一个值,并用该值和收到的确认号减1相比,如果相同就是合法的,这时候才开始真正的资源分配。
七、公平性
根据拥塞控制的原理,当有多条TCP连接共享同一条链路时:- 具有较大RTT的具有更大的吞吐量,这是因为RTT越大,连接检测到拥塞的速度越慢,这样它执行拥塞控制就越慢,如果链路出现了拥塞,具有较小RTT的连接会先发现拥塞而进入拥塞控制,在有连接进入拥塞控制后,拥塞可能就解除了,这时具有较大RTT的连接也就不需要进入拥塞控制了,因而具有较大RTT的链路就会有更好的吞吐量。
- 具有较小的RTT的连接在链路空闲时能更快的抢到可用带宽,这是因为RTT决定了连接增大拥塞窗口的频率,因此RTT越小,连接越能更快的检测到还有可用带宽。