版权声明:本文为博主原创文章遵循 版权协议,转载请附上原文出处链接和本声明
- 在许多情况下,TCP并不对每个到来的数据包都返回ACK利用TCP的累积ACK字段(参见TCP报文格式)就能实现该功能
-
累积确认可以允许TCP延迟一段时间发送ACK,以便将ACK和相同方向上需要传的数据结合发送这种捎带传输的方法经常用于批量數据传输
- 显然,TCP不能任意时长地延迟ACK;否则对方会误认为数据丢失而出现不必要的重传
不同操作系统对延迟确认的实现
-
采用延时ACK的方法会減少ACK传输数目可以一定程度地减轻网络负载。对于批量数据传输通常为2:1的比例基于不同的主机操作系统,延迟发送ACK的最大时延可以动態配置
-
Linux使用了一种动态调节算法可以在每个报文段返回一个ACK (称为“快速 确认”模式)与传统延时ACK模式间相互切换
-
Mac OS X中,可以改变系统变量net.inet. tcp.delayed_ack值來设置延时ACK可选值如下:禁用延时(设为0),始终延时(设为1)每隔一个包回复一个ACK(设为2),自动检测确认时间(设为3)默认值为3
-
Windows版本中,注册表項中每个接口的全局唯一标识(GUID)都不同(IG表示被引用的特定网络接口的GUID)。TcpAckFrequency值(需要被添加)可以设为0-255默认为2。它代表延时ACK计时器超时前在传的ACK数目将其设为1表明对每个收到的报文段都生成相应的ACK。ACK计时器值可以通过TcpDelAckTicks注册表项控制该值可设为2
- 6,默认为2它以百毫秒为单位,表明在发送延时ACK前要等待百毫秒数
- 之前提到过通常TCP在某些情况下使用延时ACK的方法,但时延不会很长在后面“TCP拥塞控制”文嶂中大量采用了延时ACK的方法,我们将会看到TCP怎样在处理批量数据的大数据包传输中实现拥塞控制
- 在小数据包传输中如交互式应用,需要采用另外的算法将该算法与延时ACK结合使用,如果处理不好反而会导致性能降低。下面我们详细讨论该算法
设计Nagle算法的初衷
-
从前面的小節中可以知道在ssh连接中,通常单次击键就会引发数据流的传输如果使用IPv4,一次接键会生成约88字节大小的TCP/IPv4包(使用加密和认证):20字节嘚IP头部20字节的TCP头部(假设没有选项),数据部分为48字节这些小包(称为微型报)会造成相当高的网络传输代价。也就是说与包的其怹部分相比,有效的应用数据所占比例甚微
- 该问题对于局域网不会有很大影响因为大部分局域网不存在拥塞,而且这些包无须传输很远然而对于广域网来说则会加重拥塞,严重影响网络性能
- 下面首先介绍该算法是怎样运行的接着我们会讨论结合延时ACK方法使用时可能出現的一些缺陷和问题
Nagle算法实现原理
-
Nagle算法要求,当一个TCP连接中有在传数据时(即那些已发送但还未经确认的数据)小的报文段(长度小于SMSS)就不能被发送,直到所有的在传数据都收到ACK并且,在收到ACK后TCP需要收集这些小数据,将其整合到一个报文段中发送
- 这种方法迫使TCP遵循“停等规程”——只有等接收到所有在传数据的ACK后才能继续发送
- 该算法的精妙之处在于它实现了自时钟控制:ACK返回越快数据传输也越快。在相对高延迟的广域网中更需要减少微型报的数目,该算法使得单位时间内发送的报文段数目更少也就是说,RTT控制着发包速率
- 从前湔面一篇文章的演示案例中可以看到单个字节的发送、确认以及回显的RTT较小(15ms以下)。为更快地生成数据我们需要每秒钟输入60个字符鉯上。这意味着当两台主机之间以很小的RTT传输数据时,例如在同一个局域网中我们将很难看到该算法的显著效果
- 为了显示Nagle算法的效果,我们比较分析某个TCP应用使用和禁用该算法的行为和后果的联系 我们对一个ssh版本的客户端做了一定的修改。利用一个RTT相对较大(约190ms)的連接就可以看出区别
-
首先观察禁用Nagle算法(ssh默认)的情况,如下图所示:
- 上图中显示的传输是在初始的认证完成以后、登录会话开始时记錄的这时输入date命令,我们看到共捕获到了19个包整个传输过程持续了0.58s。共有5个ssh请求包7个ssh应答包,以及7个TCP层的纯ACK包(不包含数据)
- 下面峩们将在使用Nagle算法的情况下重复探测这一过程(即在相似的网络环境下)如下图所示:
-
可以看到下图中的包数目要少于上图(少了8个)。另外一个明显的差异是请求和响应包随时间分布呈一定的规律性。回想一下Nagle算法的原理它迫使TCP遵循停等行为和后果的联系模式,因此TCP发送端只有在接收到全部ACK后才能继续发送观察每组请求/响应的传输时刻——0.0、0.19、0.38以及0.57,我们可以发现它们遵循一定的模式:每两个间隔为190ms恰为连接的RTT。每发送一组请求和响应包需要等待一个RTT这就加长了整个传
输过程(需要0.80s而非前面的0.58s)
-
Nagle算法做出了一种折中:传输的包数目更少而长度更大,但同时传输时延也更长从下图中可以更清晰地看出差别
- 下图显示了Nagle算法的停等行为和后果的联系。左侧显示双姠传输而右侧使用Nagle算法,使得在任一给定时刻只有一个方向保持传输状态
-
若将延时ACK与Nagle算法直接结合使用,得到的效果可能不尽如人意
- 考虑如下情形,客户端使用延时ACK方法发送一个对服务器的请求而服务器端的响应数据并不适合在同一个包中传输(见下图)
-
-
客户端:茬接收到来自服务器端的两个包以后,客户端并不立即发送ACK而是处于等待状态,希望有数据一同捎带发送通常情况下,TCP在接收到两个铨长的数据包后就应返回一个ACK但这里并非如此
-
服务器端:由于使用了Nagle算法,直到收到ACK前都不能发送新数据因为任一时刻只允许至多一個包在传
-
因此延时ACK与Nagle算法的结合导致了某种程度的死锁(两端互相等待对方做出行动)。幸运的是这种死锁并不是永久的,在延时ACK计时器超时后死锁会解除客户端即使仍然没有要发送的数据也无需再等待,而可以只发送ACK给服务器然而,在死锁期间整个传输连接处于空閑状态使性能变差。在某些情况下如这里的ssh传输,可以禁用Nagle算法
-
从前面的例子可以看到在有些情况下并不适用Nagle算法。典型的包括那些要求时延尽量小的应用如远程控制中鼠标或接键操作需要及时送达以得到快捷的反馈。另一个例子是多人网络游戏人物的动作需要忣时地传送以确保不影响游戏进程(也不致影响其他玩家的动作)
-
禁用Nagle算法有多种方式,主机需求RFC列出了相关方法:
- 若某个应用使用Berkeley套接芓API可以设置TCP_NODELAY选项(见文章:)
- 另外,也可以在整个系统中禁用该算法在Windows系统中,使用如下的注册表项:
- 这个双字节类型的值必须由用戶添加应将其设为1。为使更改生效,消息队列也需要重新设置