c - 接收方的延迟 ACK 与发送方的 RTO

标签 c linux sockets tcp

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

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

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

最佳答案

关于延迟的 ACK 时序,RFC 1122 说:

A TCP SHOULD implement a delayed ACK, but an ACK should not be excessively delayed; in particular, the delay MUST be less than 0.5 seconds, and in a stream of full-sized segments there SHOULD be an ACK for at least every second segment.

所以这取决于实现,当然还取决于是否会降低应用程序性能。
在 Linux 内核中,它们不会通过计时器或固定间隔发送延迟的 ACK,正如您在下面的代码中看到的那样,它们根据条件的行为有所不同。 正如您在 net/ipv4/tcp_input.c 中看到的,他们在评论中说:

There is something which you must keep in mind when you analyze the behavior of the tp->ato delayed ack timeout interval. When a connection starts up, we want to ack as quickly as possible. The problem is that "good" TCP's do slow start at the beginning of data transmission. The means that until we send the first few ACK's the sender will sit on his end and only queue most of his data, because he can only send snd_cwnd unacked packets at any given time. For each ACK we send, he increments snd_cwnd and transmits more of his queue. -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);
}

关于c - 接收方的延迟 ACK 与发送方的 RTO,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35383985/

相关文章:

c# - 在 PCL (.Net 4.5 + phone 8) 中使用 System.Net.Sockets

C 字符串 malloc(输出)

c - 从 Cuda 传输大量可变内存

c++ - clock_gettime() 返回错误的结果(VirtualBox 上的 Debian wheezy)

linux - bash 中的静默 while 循环

algorithm - 测量两台机器之间的链路质量

c++ - 通过本地代理将 GET 发送到 google。 C++。 Linux。传输控制协议(protocol)

c - C中将字符串添加到char数组并用\0分隔

c - OpenCL:内核之间的同步

PHP 和构建过程 (/.configure, make and install) : orientation, 请