如果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);
}

07-28 02:58
查看更多