Delay ack(延迟确认)
正常情况下服务器收到一个请求时就会立即回复ACK确认给客户端,然后客户端再发送下一个包,服务器再进行回复。有时候服务器回复的ACK包有长度,但实际内容长度为0,这也没关系属于正常的。不过一次发送一次确认效率比较低,能不能收多次批量确认一次呢?这就是延迟确认。
Delay ack是说收到包不立即回复ack,而是等一会儿默认200毫秒,看看这段时间是否有还有包发过来(属于同一客户端)如果有就一起发送ACK确认,如果超时了还没有等到那么就直接发送这一个确认包。在延迟确认期间ack不是立即发送而是等待200毫秒,如果有就一起发送,或者如果凑够2个ack包就一起发送;如果在等200毫秒还没有就发送者一个ACK包。
所以正常情况下抓包都是一个数据包后面紧跟一个ACK确认包。
Nagle算法
如果服务器接收窗口大于MSS并且客户端要发送的数据大于一个MSS长度(1460)的就立即发送;否则就等待前面发出去包是不是还没有ACK,如果没有剩下的小包就等前面的ack返回之后再发送。也就是说包很小,然后又有包发给服务器而且还没有收到ack,那么就等等ack返回之后再发送剩下的包。
如果客户端启用Nagle并且服务器启用了delay ack会怎么样?
比如客户端发送一个HTTP请求给服务器,这个请求有1560个字节,握手的MSS是1460个字节。那么这1560个字节就会分成2个TCP包,第一个1460,第二个100。第一个发送出去后,服务器收到,因为延迟确认,服务器等待200毫秒,客户端开启了Nagle(默认开启)由于第二个包100字节很小,所有它就等待前一个包的ack返回后再进行发送,这时双方就进入互相等待的阶段,直到200毫秒超时,服务器发送ack,然后客户端再发送剩余的一个包。
再说一个例子引用自:http://www.stuartcheshire.org/papers/nagledelayedack/
传输数据是99,900字节,速度5.2M每秒;如果传输数据是100,000字节速度是2.7M每秒。多了10字节为什么速度下降这么多?
99,900 bytes = 68 全尺寸包 1448字节每个包,另外剩余1436字节最后一个包 |
100,000 bytes = 69 全尺寸包 1448字节每个包,另外剩余88字节最后一个包 |
说明:一个MSS是1460,为什么上面一个包是1448呢?因为那12个字节,因为Windows操作系统是1460,苹果或者其他操作系统多了一个时间戳选项,TCP分段大小就少了所以是1448个字节。上面的例子是按照Linux操作系统来说的。
68个包会立即发发送,因为68是偶数,所以服务器最后肯定收到2个包,然后发送ACK给客户端,然后客户端立即发送剩余的1436字节,整个过程没有等待。如果是69个包由于是奇数,服务器最后一次收到是1个包,所以等待200毫秒,然后客户端由于剩下88个字节也会等待,这样就增加了整体传输时间,超时之后再发送最后一个88个字节。