[tcp/ip] tcp delayed ack

触发机制

被delay的ack包,什么时候发送出来?

  1. 到达500ms (这个值根据实现的不同而不同,RFC要求最多不能超过500,linux的实现是200)
  2. 每两个数据包回一个ack
  3. 由反向数据包发送带回。

优点

delayed ack可以提供一个机会给应用程序。让三个回应报合并成一个回应包。

三个分别为:ack,窗口更新,应用层回应。

应用层回应显然是应用程序主动发回的。窗口更新也跟应用层有关,是因为应用程序从buffer里读走了数据,窗口自然会发生更新。

所以,ack延迟500毫秒,最大的好处是为了让这三个信息从一个包里携带过去。

缺点

write write read 问题

当delayed ack和nagle算法同时使用时,会引起write write read问题。 这个问题的本质是,传输层因为启用了这两个算法,而导致了应用层在等待传输层的问题。

举例:A与B通信,a发送1和2然后读取,b收到1和2后发送他们的和3给a,a最终收到1和2的和3.

这个场景的前提是1已经发出去了。然后a发送2并堵塞读。由于2已经交付给了操作系统。所以应用程序a便阻塞在了读操作上面。

这个时候,应1的ack还没有回来。所以a所在的操作系统因为nagle算法并不会把2发出去。

b所在的操作系统收到了1并交付给了应用程序b。但是b还没有收到加法的第二个操作数2,所以也不会主动发送他们的和3.

这个是a和b所在的两个tcp协议栈就在相互等待对方,而导致原本可应该更快处理的两个应用层程序出现了堵塞。a在等待1的ack,b在等待第二个操作数2。

这个僵局直到,b的delay ack到达500毫秒的超时发送了1的ack才会被打破。

这就是 write write read问题。

慢启动

TCP慢启动是为了以指数增长的趋势快速逼近最大带宽。很显然,在这个前提下,delayed ack会使逼近速度降低。

所以在慢启动过程中,快速确认(quick ack)也是被启动的。linux里有这样一个宏定义的值,来达到这个目的

/* Maximal number of ACKs sent quickly to accelerate slow-start. */
#define TCP_MAX_QUICKACKS 16U

配置方法

linux下,使用setsockopt()可以对这两个特性,delayed ack和nagle算法进行配置。

  • nagle: 选项 TCP_NODELAY 用来控制发包侧的行为。
  • delayed ack: 选项 TCP_QUICKACK 用来控制收包侧的行为。
    • 值得一提的是,delay ack与quick ack(快速确认)直接的转换是协议栈动态调节的,即使在同一条TCP连接里,显式设置的该选项

也会被OS在恰当的时机里调节回去。

参考:man 7 tcp

参考

https://en.wikipedia.org/wiki/TCP_delayed_acknowledgment

原文地址:https://www.cnblogs.com/hugetong/p/13208823.html