TCP协议以确认(ACK,acknowledgment)时钟为基础(即所谓的self-clock),发送者根据接收到的已发送数据的ACK,判断是否可以进一步发送数据。具体地,TCP的ACK机制以如下方式影响发送过程:
到达发送者的ACK的时间指明了RTT。
ACK携带了接收者通告的窗口大小,即接收者在任意时间点上可能接收的最多数据量。在发送完这个窗口的数据时,只有接收到ACK之后才能发送后面的数据包。
通过使用“拥塞窗口”,TCP限制发送过多数据避免引起网络拥塞。ACK可以反映当前网络的拥塞状态,从而调整拥塞窗口。
TCP使用两种ACK模式,即:快速ACK和延迟ACK。快速ACK用在启动TCP连接时,可以保证拥塞容器迅速增大。然后TCP使用延迟ACK模式:多个(通常是两个)包才产生一个ACK。TCP根据网络拥塞的情况在两种模式间互相转换。
细节
进入快速ACK模式时,初始化以下参数:
重置pingpong标志
ACK超时时长(ATO)设为最小。
调用tcp_incr_quickack计算能够快速发送的ACK数量,由接收窗口和包大小决定。这个策略会快速ACK半个接收窗口的数据包。(计算好的参数保存在quick中)
在每次接收到数据包时,按需要调整MSS的值。
检查当前模式()
如果满足以下条件,TCP就处于快速ACK模式:
pingpong为0
可以发送的快速ACK数量不为0(quick)
在ack待决标志变量(ack pending flag)设置了ICSK_ACK_SCHED标志就意味着就调度了一个ACK。
接收数据的处理当处于ESTABLISHED状态接收到数据时 () ,执行以下动作:
处理数据接收事件 ()。
如果包含有数据,调度一个ACKACK其数据。
MSS处理 ()。
检查接收到的包大小,如果它导致了MSS的变化,这也会影响快速ACK的发送数量。
如果接收到的包尺寸小于MSS,就会立即将一个ACK推送(push)出去。(小数据包通常意味着发送者没有数据可发了)
如果是第一次接收数据,ATO(ACK超时)还没有设置,因此可以使用它判断是不是第一次接收到数据。接收到之后的数据包时,数据包的间隔m用于调整ATO。TCP_ATO_MIN是ATO的最小值。如果m>ATO,说明可以放松ATO一点。但一定要保证ATO不要超过RTO(重传超时),如果数据包到达间隔超过RTO,这很可能意味着网络发生了阻塞。此时,TCP调用,切换到快速ACK模式,在把接收数据复制用户空间后发送ACK。
根据模式发送ACK在处理接收事件时,如果发现有乱序的数据包,就将SACK信息添加到待发送ACK报文上;如果接收到的数据包填充了乱序队列中“空洞”,就立即重置pingpong为0,从而立即发送ACK;如果接收到窗口外的数据,也会调度快速ACK的ACK。
ACK的发送针对接收到的数据发送ACK ()
检查以上步骤是不是已经发送过ACK了。
如果满足以下任一条件就立即发送ACK,否则发送延迟ACK。
接收到完整的frame (包尺寸大于MSS),并且发送方的接收窗口可以接纳这些数据。
快速ACK模式被激活,并且quick不为0,并且 pingpong 不为0。
接收到乱序数据,并且我们已经缓冲有乱序数据(这次或者以前接收到的)。
在准备ACK())时,如果发现内存分配失败,就会调度一个ACK并把延时ACK定时器设置成最大间隔。每发送一个ACK就将quick减一,ACK的pending和blocked标志会被复位为0,并会停止延迟定制器。quick减为0时,标志着延迟ACK模式的开始,此时ATO设置为最小值TCP_ATO_MIN。
延迟ACK的发送() 调整ATO的上限:如果pingpong置为1,并且已经推送了ack,就将max_ato设置为TCP_DELACK_MAX(20U),否则设置为50U。
下限:ATO的最小值为TCP_DELACK_MIN(4U),如果测量出TCP连接的RTT(SRTT)落在范围{TCP_DELACK_MIN,TCP_DELACK_MAX}之间,则取ATO为以下两者的最小值:SRTT、在处理MSS时())计算的ATO。
在延迟ACK定时器已经启动时,如果ack已经标记为blocked,或者延迟ACK定时器马上就会超时,就会马上发送一个ACK,或者刚刚计算得到的延迟ACK定时器超时小于现有设置,就不会改变现有设置。否则,就使用新计算的ATO值重启延迟ACK定时器。
延迟ACK定时器的超时动作延迟ACK定时器过期执行 ()
在以下场景下,不会发送延迟ACK:
处理接收数据事件的代码与定时器代码需要互斥访问公共的数据结构,如果定时器获取spin lock失败,就将ACK设置为blocked的,并重新以 TCP_DELACK_MIN 间隔重新调度定时器。
如果RTT测量的结果大于延迟ACK定时器的超时间隔,就会两者的差值重启定时器。
TCP连接关闭。
没有设置 TCP_ACK_TIMER。
在以下场景下,会发送延迟ACK:如果调度过ACK并且pingping为0,这意味着ATO过短。ATO值会被翻倍,但最大值不超过RTO。如果调度过ACK并且pingping为1,这意味着ATIO过长,ATO值会设置为最小值, TCP_ATO_MIN。
把数据将会给应用层在把接收到的数据复制到用户进程时,ACK会在以下情况下立即发送:
有处于blocked状态的ACK
应用程序从队列接收了小于1个MSS的数据。
从零窗口条件下恢复时。
原文链接:
维护:
翻译: raise.sail@gmail.com