后面详细分析 先上传 之前总结查看源码后的总结
Nagle算法的基本定义是任意时刻,最多只能有一个未被确认的小段。所谓“小段”,指的是小于MSS尺寸的数据块,所谓“未被确认”,是指一个数据块发送出去后,没有收到对方发送的ACK确认该数据已收到。也就是没有收到ack 的时候不会再次发送数据出去。该算法的优越之处在于它是自适应的,确认到达的越快,数据也就发送的越快;而在希望减少微小分组数目的低速广域网上,则会发送更少的分组。
Nagle算法的规则(可参考tcp_output.c文件里tcp_nagle_check函数注释):
(1)如果包长度达到MSS,则允许发送;
(2)如果该包含有FIN,则允许发送;
(3)设置了TCP_NODELAY选项,则允许发送;
(4)未设置TCP_CORK选项时,若所有发出去的小数据包(包长度小于MSS)均被确认,则允许发送;
(5)上述条件都未满足,但发生了超时(一般为200ms),则立即发送。
Nagle算法只允许一个未被ACK的包存在于网络,它并不管包的大小,因此它事实上就是一个扩展的停-等协议(停止等待ARQ协议),只不过它是基于包停-等的,而不是基于字节停-等的。Nagle算法完全由TCP协议的ACK机制决定,这会带来一些问题,比如如果对端ACK回复很快的话,Nagle事实上不会拼接太多的数据包,虽然避免了网络拥塞,网络总体的利用率依然很低。
可以马上发送,不使用Nagle的情况:
1. 此skb不是发送队列的最后一个包。对于发送队列中间的包,使用Nagle也没用,因为它们无法再获得新的数据。
2. 发送的是紧急数据(urgent data)。顾名思义,紧急数据应该马上发送的,怎么能被耽误呢?
3. 处于F-RTO中。此阶段会发送两个小探测包探测超时是否为虚假的,此时不能够被耽误,所以禁用Nagle。
4. 数据包包含结束标志(TCPHDR_FIN)。表明发送即将结束,再用Nagle延迟就多此一举了。
5. 数据包满负荷。既然都已经满负荷了,还等什么。
6. 没设置TCP_CORK (TCP_NAGLE_CORK,2),设置了TCP_NODELAY (TCP_NAGLE_OFF,1)。
7. 没有设置TCP_CORK,且网络中不存在小包
反过来看,可以使用Nagle时需符合以下条件:
1. 此skb是发送队列的最后一个包。
2. 发送的不是紧急数据。
3. 不处于F-RTO中。
4. 数据包不含FIN标志。
5. 数据包大小小于mss_now,不是满负荷的。
6. 设置了TCP_NAGLE_CORK,或者,
没有设置TCP_NODELAY,且网络中存在小包。
列中间的数据包无效,因为只有发送队列最后
一个数据包才有机会获得新的数据,形成更大的包。
延迟确认机制(TCP delayed acknowledgment)
wiki的解释https://en.wikipedia.org/wiki/TCP_delayed_acknowledgment
1989 RFC 1122定义,全名Delayed Acknowledgment,简称延迟ACK,翻译为延迟确认。
与Nagle算法一样,延迟ACK的目的也是为了减少网络中传输大量的小报文数,但该报文数是针对ACK报文的。
一个来自发送端的报文到达接收端,TCP会延迟ACK的发送,希望应用程序会对刚刚收到的数据进行应答,这样就可以用新数据将ACK捎带过去。
delay-ack
通常Server在接收到从Client发送过来的数据时,并不马上发送ACK,而是等一个规定时延,看看本机是否有数据要反馈给Client,如果有,就将数据包含在此ACK包中,以前发送给Client。一般情况下这个时延为200ms。