Linux-ETIMEDOUT的TCP connect()失败 [英] Linux - TCP connect() failure with ETIMEDOUT

查看:294
本文介绍了Linux-ETIMEDOUT的TCP connect()失败的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

对于TCP客户端,connect()调用TCP服务器.

理查德·史蒂文斯(Richard Stevens)撰写的

UNIX®网络编程书如下.

如果客户端TCP没有收到对其SYN段的响应,则返回ETIMEDOUT. 4.4BSD, 例如,在调用connect时发送一个SYN,在另外6秒后发送另一个, 24秒后(TCPv2的第828页).如果总共75秒后未收到任何回应,则 错误返回.

在Linux中,我想知道什么是重试机制(多少次以及相隔多远).询问是因为对于TCP客户端connect()调用,我收到ETIMEDOUT错误.此套接字具有O_NONBLOCK选项,并由epoll()监视事件.

如果有人可以指向我在代码中的哪个位置实现此重试逻辑,这也将有所帮助.我尝试从net/ipv4/tcp_ipv4.c开始以tcp_v4_connect()开头,但是很快就迷路了.

解决方案

根据所测量的往返时间来缩放超时.

tcp_connect()设置计时器:

    /* Timer for repeating the SYN until an answer. */
    inet_csk_reset_xmit_timer(sk, ICSK_TIME_RETRANS,
                              inet_csk(sk)->icsk_rto, TCP_RTO_MAX);

icsk_rto将使用每个目标重传超时;如果来自先前目标的先前度量标准可通过先前连接获得,则将重新使用该度量标准. (有关详细信息,请参见tcp(7)中的tcp_no_metrics_save讨论.)如果未保存任何度量标准,则内核将回退到默认RTO值:

#define TCP_RTO_MAX     ((unsigned)(120*HZ))
#define TCP_RTO_MIN     ((unsigned)(HZ/5))
#define TCP_TIMEOUT_INIT ((unsigned)(1*HZ))     /* RFC2988bis initial RTO value */
#define TCP_TIMEOUT_FALLBACK ((unsigned)(3*HZ)) /* RFC 1122 initial RTO value, now
                                                 * used as a fallback RTO for the
                                                 * initial data transmission if no
                                                 * valid RTT sample has been acquired,
                                                 * most likely due to retrans in 3WHS.
                                                 */

tcp_retransmit_timer()在底部附近有一些代码可用于重新计算延迟:

    inet_csk_reset_xmit_timer(sk, ICSK_TIME_RETRANS, icsk->icsk_rto, TCP_RTO_MAX);
    if (retransmits_timed_out(sk, sysctl_tcp_retries1 + 1, 0, 0))
            __sk_dst_reset(sk);

retransmits_timed_out()首先将执行线性补偿,然后执行指数补偿.

我认为,总的来说,总的来说,您可以合理地预期大约120秒才能从connect(2)返回ETIMEDOUT错误,除非内核有充分的理由怀疑远程对等体应该更快地答复. /p>

For a TCP client connect() call to a TCP server..

UNIX® Network Programming book by Richard Stevens says the following..

If the client TCP receives no response to its SYN segment, ETIMEDOUT is returned. 4.4BSD, for example, sends one SYN when connect is called, another 6 seconds later, and another 24 seconds later (p. 828 of TCPv2). If no response is received after a total of 75 seconds, the error is returned.

In Linux I would like know what is the retry mechanism (how many times and how far apart). Asking because for a TCP client connect() call I am getting ETIMEDOUT error. This socket has O_NONBLOCK option and monitored by epoll() for the events.

If someone can point to me where in the code this retry logic is implemented that would be helpful too. I tried following a bit starting with tcp_v4_connect() from net/ipv4/tcp_ipv4.c, but lost my way pretty soon..

解决方案

The timeout is scaled based on the measured round-trip time.

tcp_connect() sets up a timer:

    /* Timer for repeating the SYN until an answer. */
    inet_csk_reset_xmit_timer(sk, ICSK_TIME_RETRANS,
                              inet_csk(sk)->icsk_rto, TCP_RTO_MAX);

The icsk_rto will use a per-destination re-transmission timeout; if previous metrics from the destination is available from previous connections, it is re-used. (See the tcp_no_metrics_save discussion in tcp(7) for details.) If no metrics are saved, then the kernel will fall back to a default RTO value:

#define TCP_RTO_MAX     ((unsigned)(120*HZ))
#define TCP_RTO_MIN     ((unsigned)(HZ/5))
#define TCP_TIMEOUT_INIT ((unsigned)(1*HZ))     /* RFC2988bis initial RTO value */
#define TCP_TIMEOUT_FALLBACK ((unsigned)(3*HZ)) /* RFC 1122 initial RTO value, now
                                                 * used as a fallback RTO for the
                                                 * initial data transmission if no
                                                 * valid RTT sample has been acquired,
                                                 * most likely due to retrans in 3WHS.
                                                 */

tcp_retransmit_timer() has some code near the bottom for recalculating the delay:

    inet_csk_reset_xmit_timer(sk, ICSK_TIME_RETRANS, icsk->icsk_rto, TCP_RTO_MAX);
    if (retransmits_timed_out(sk, sysctl_tcp_retries1 + 1, 0, 0))
            __sk_dst_reset(sk);

retransmits_timed_out() will first perform a linear backoff then an exponential backoff.

I think the long and the short of it is that you can reasonably expect roughly 120 seconds before getting ETIMEDOUT error returns from connect(2) unless the kernel has good reason to suspect that the remote peer should have replied sooner.

这篇关于Linux-ETIMEDOUT的TCP connect()失败的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆