如果H1打开到H2的TCP连接,则H1向H2发送一个小数据包(
TCP如何确保在H1处的RTO计时器在收到延迟的ACK之前不会过期?
是否正确理解Linux默认情况下的最小RTO为200毫秒,所以如果网络速度很快(RTO保持最小200毫秒)并且数据包在从H1到H2的途中丢失,那么H1将在200ms内重试?如果网络很慢,那么H1可能会等待200ms以上?
最佳答案
关于延迟的ACK时序,RFC 1122说:
TCP应该实现延迟的ACK,但是ACK不应
过度延迟;特别是,延迟必须是
不到0.5秒,并以全尺寸显示
至少应该每秒有一个ACK
分割。
因此,它取决于实现方式,当然也取决于能否降低应用程序性能。
在Linux内核中,它们不会按计时器或固定间隔发送延迟的ACK,正如您在以下代码中看到的那样,它们的行为因条件而异。
正如您在net/ipv4/tcp_input.c
中看到的那样,他们在评论中说:
在分析以下内容时,您必须记住一些事情
tp-> ato延迟ack超时间隔的行为。当一个
连接启动后,我们希望尽快确认。的
问题是“好的” TCP在数据开始时启动缓慢
传输。也就是说,在我们发送前几个ACK之前,
发件人将坐在他的末端,只将他的大部分数据排队,因为
他只能在任何给定时间发送snd_cwnd未经确认的数据包。对于
我们发送的每个ACK,他都会递增snd_cwnd并发送更多他的
队列。 -戴夫
static void tcp_event_data_recv(struct sock *sk, struct sk_buff *skb)
{
struct tcp_sock *tp = tcp_sk(sk);
struct inet_connection_sock *icsk = inet_csk(sk);
u32 now;
inet_csk_schedule_ack(sk);
tcp_measure_rcv_mss(sk, skb);
tcp_rcv_rtt_measure(tp);
now = tcp_time_stamp;
if (!icsk->icsk_ack.ato) {
/* The _first_ data packet received, initialize
* delayed ACK engine.
*/
tcp_incr_quickack(sk);
icsk->icsk_ack.ato = TCP_ATO_MIN;
} else {
int m = now - icsk->icsk_ack.lrcvtime;
if (m <= TCP_ATO_MIN / 2) {
/* The fastest case is the first. */
icsk->icsk_ack.ato = (icsk->icsk_ack.ato >> 1) + TCP_ATO_MIN / 2;
} else if (m < icsk->icsk_ack.ato) {
icsk->icsk_ack.ato = (icsk->icsk_ack.ato >> 1) + m;
if (icsk->icsk_ack.ato > icsk->icsk_rto)
icsk->icsk_ack.ato = icsk->icsk_rto;
} else if (m > icsk->icsk_rto) {
/* Too long gap. Apparently sender failed to
* restart window, so that we send ACKs quickly.
*/
tcp_incr_quickack(sk);
sk_mem_reclaim(sk);
}
}
icsk->icsk_ack.lrcvtime = now;
tcp_ecn_check_ce(tp, skb);
if (skb->len >= 128)
tcp_grow_window(sk, skb);
}