【问题标题】:Very strange connection times in LinuxLinux 中非常奇怪的连接时间
【发布时间】:2016-03-14 13:54:06
【问题描述】:

我创建了一个带有 backlog 1 的侦听套接字,并将 64 个套接字连接到它。

socket.c

#define _POSIX_C_SOURCE 199309L

#include <arpa/inet.h>
#include <stdio.h>
#include <sys/socket.h>
#include <sys/time.h> 
#include <time.h>

int main() {
    int server_socket = socket(AF_INET, SOCK_STREAM, 0);
    struct sockaddr_in server_address = {0};
    server_address.sin_family = AF_INET;
    server_address.sin_addr.s_addr = htonl(INADDR_ANY);
    server_address.sin_port = htons(8000); 
    bind(server_socket, (struct sockaddr*)&server_address, sizeof(server_address)); 
    if (listen(server_socket, 1) == 0) {
        printf("Listening\n");
    } else {
        printf("Failed to listen\n");
        return 1;
    }

    for (int i = 0; i < 64; i++) {
        int client_socket = socket(AF_INET, SOCK_STREAM, 0);
        struct timespec start;
        clock_gettime(CLOCK_MONOTONIC, &start);
        if (connect(client_socket, (struct sockaddr*)&server_address, sizeof(server_address)) == 0) {
            struct timespec end;
            clock_gettime(CLOCK_MONOTONIC, &end);
            double elapsed = end.tv_sec - start.tv_sec + (end.tv_nsec - start.tv_nsec) / 1e9;
            printf("Connected socket #%d in %.3lfs\n", i, elapsed);
        } else {
            printf("Failed to connect socket #%d\n", i);
        }
    }
}

输出:

$ gcc -o socket -std=c99 socket.c
$ ./socket
Listening
Connected socket #0 in 0.000s
Connected socket #1 in 0.000s
Connected socket #2 in 0.000s
Connected socket #3 in 0.000s
Connected socket #4 in 1.000s
Connected socket #5 in 0.000s
Connected socket #6 in 3.004s
Connected socket #7 in 0.000s
Connected socket #8 in 3.004s
Connected socket #9 in 0.000s
Connected socket #10 in 3.004s
Connected socket #11 in 0.000s
Connected socket #12 in 3.004s
Connected socket #13 in 0.000s
Connected socket #14 in 3.004s
Connected socket #15 in 0.000s
Connected socket #16 in 3.004s
Connected socket #17 in 0.000s
...

前四个连接是瞬时的,第五个需要 1 秒,然后连接在 0 到 3 秒之间振荡,直到所有套接字都连接并退出程序。这种行为是 100% 可重复的。

我已广泛阅读有关 TCP 连接、Linux 网络文档和 other resources 的内容。

但我仍然无法解释发生了什么。

为什么连接时间变化如此之大?


系统信息

$ uname -a
Linux paul 3.19.0-51-generic #58~14.04.1-Ubuntu SMP Fri Feb 26 22:02:58 UTC 2016 x86_64 x86_64 x86_64 GNU/Linux

/etc/sysctl.conf 为空。)

【问题讨论】:

  • 如果您将connect() 更改为像127.0.0.1 这样的真实IP 而不是INADDT_ANY,会发生什么变化?如果你真的 accept() 传入的连接?

标签: linux sockets tcp


【解决方案1】:

listen 的文档对此进行了解释,“如果底层协议支持重传,则可以忽略该请求,以便稍后重新尝试连接成功”。如果您提出积压,您会发现延迟开始的时间点发生了变化。

【讨论】:

  • 好的。但是前4快在哪里?为什么只有其他所有连接?哪些超时或设置导致连接时间过长?我正在寻找对 Linux TCP 的理解,而不是“让这个数字足够高,然后会发生其他事情”。
  • @PaulDraper 这是一个竞争条件。有一段代码添加到侦听队列中,还有一段代码正在耗尽侦听队列。如果在侦听队列中有空间时发生连接,它会立即完成。如果没有,它会延迟到重新传输。
  • 发生交替是因为您在尝试下一个连接之前等待一个连接完成。因此,必须等待的连接几乎总是将监听队列留空以进行下一次尝试。
【解决方案2】:

正如 David Schwartz 所说,这是由于您的积压。处理 SYN 请求的 TCP 代码认为接受队列已满并且 SYN 队列也已满。 如所见here

1287         /* Accept backlog is full. If we have already queued enough
1288          * of warm entries in syn queue, drop request. It is better than
1289          * clogging syn queue with openreqs with exponentially increasing
1290          * timeout.
1291          */
1292         if (sk_acceptq_is_full(sk) && inet_csk_reqsk_queue_young(sk) > 1) {
1293                 NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_LISTENOVERFLOWS);
1294                 goto drop;
1295         }

一旦达到上述条件,您的 SYN 数据包就会被丢弃。客户端的重传发生在 3 秒后(初始 SYN),被接受

如果将 backlog 设置为 65,则连接不会出现任何延迟

【讨论】:

    猜你喜欢
    • 2012-07-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-05-28
    • 1970-01-01
    • 2012-04-13
    • 1970-01-01
    • 2017-02-17
    相关资源
    最近更新 更多