接收方的延迟ACK与发送方的RTO相关

时间:2016-02-13 18:53:55

标签: c linux sockets tcp

如果H1打开到H2的TCP连接,则H1向H2发送一个小数据包(< MSS)(H2不响应数据),H2发送延迟ACK需要多长时间?

TCP如何确保H1上的RTO定时器在收到延迟的ACK之前不会到期?

是否正确理解Linux默认情况下RTO最小为200ms,因此如果网络速度很快(RTO保持在最小200ms)并且数据包在从H1到H2的途中丢失,那么H1将在200ms内重试?如果网络速度慢,那么H1可能会等待超过200毫秒?

1 个答案:

答案 0 :(得分:0)

关于延迟的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并传输更多他的    队列。 -DaveM

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