gpt4 book ai didi

c - 为什么在 ~16370 个套接字连接后会有长时间的停顿?

转载 作者:行者123 更新时间:2023-12-03 11:52:51 26 4
gpt4 key购买 nike

我一直在使用 sockets API 来了解它是如何工作的。

我写了两个小程序:

  • 服务器在 8080 上监听流连接。它向任何连接到它的人发送一条简单的消息。
  • 客户端连接到 127.0.0.1:8080,并将接收到的内容转储到标准输出。它按顺序重复此 20000 次。

  • 消息以极快的速度流向大约 16370 次,然后暂停数十秒,然后再次开始快速移动以完成 20000 个连接。

    我重复这个实验几次,我在 16370、16371 和 16372 抓到了它。重复实验的结果惊人地一致。

    我的问题是:为什么它需要在 ~16370 次迭代后暂停?这里的瓶颈是什么?

    FWIW,我在 macOS Sierra 上。

    我像这样运行服务器代码:
    clang -Wall -Werror -Wpedantic server.c -o server.out && ./server.out

    和这样的客户端代码:
    clang -Wall -Werror -Wpedantic client.c -o client.out && time ./client.out

    这是两个程序:

    服务器.c
    #include <errno.h>
    #include <netdb.h>
    #include <netinet/in.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <sys/socket.h>
    #include <sys/types.h>
    #include <unistd.h>

    #define PORT 8080
    #define MAXMSG 512

    int make_socket(int port) {
    int sock;
    struct sockaddr_in name;

    sock = socket(PF_INET, SOCK_STREAM, 0);
    if (sock < 0) {
    perror("socket");
    exit(1);
    }

    name.sin_family = AF_INET;
    name.sin_port = htons(port);
    name.sin_addr.s_addr = htonl(INADDR_ANY);
    if (bind(sock, (struct sockaddr*) &name, sizeof(name)) < 0) {
    perror("bind");
    exit(1);
    }
    return sock;
    }

    int main(int argc, char** argv) {
    const char hello[] = "Hello visitor ";
    char buffer[MAXMSG];
    int sk;
    unsigned long count = 0;
    strcpy(buffer, hello);

    sk = make_socket(PORT);
    listen(sk, 10);

    printf("ready\n");
    for (;;) {
    count++;
    sprintf(buffer + strlen(hello), "%lu", count);
    int s = accept(sk, NULL, NULL);
    if (send(s, buffer, strlen(buffer) + 1, 0) < 0) {
    perror("send");
    exit(1);
    }
    close(s);
    printf("data socket (%d) message sent (%s)\n", s, buffer);
    }
    }

    客户端.c
    #include <arpa/inet.h>
    #include <errno.h>
    #include <netdb.h>
    #include <netinet/in.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <sys/socket.h>
    #include <sys/types.h>
    #include <unistd.h>

    #define PORT 8080
    #define MAXMSG 512

    int make_socket() {
    int sock;

    sock = socket(PF_INET, SOCK_STREAM, 0);
    if (sock < 0) {
    perror("socket");
    exit(1);
    }

    return sock;
    }

    int main(int argc, char** argv) {
    char buffer[MAXMSG];
    int sk;
    size_t i;
    struct sockaddr_in addr;
    strcpy(buffer, "Hello world!");

    for (i = 0; i < 20000; i++) {
    sk = make_socket();
    addr.sin_family = AF_INET;
    addr.sin_port = htons(PORT);
    addr.sin_addr.s_addr = inet_addr("127.0.0.1");
    connect(sk, (struct sockaddr*) &addr, sizeof(addr));
    recv(sk, buffer, strlen(buffer) + 1, 0);
    close(sk);
    printf("socket (%d) message = %s\n", sk, buffer);
    }
    }

    这是我得到客户端的最后一个标准输出:
    socket (3) message = Hello visitor 16369
    socket (3) message = Hello visitor 16370
    socket (3) message = Hello visitor 16371
    socket (3) message = Hello visitor 16372

    最佳答案

    您很可能正在达到一个称为 Ephemeral Port Range 的限制。在您的操作系统上。相同的原则适用于所有基于 IP 的操作系统。

    每当建立套接字连接时,都会为请求分配一个端口,并与建立连接的接口(interface)相关联。一旦此套接字关闭,端口就会进入称为 TIME_WAIT 的状态。有效地将端口放在工作台上一段时间,以确保不会过早重复使用。这是为了防止 Internet 中的潜在数据包迟到并导致问题。

    临时端口范围在 Linux 上指定为 /proc/sys/net/ipv4/ip_local_port_range .

    您可以使用以下命令在 MacOS 上显示这些:
    sysctl net.inet.ip.portrange.first net.inet.ip.portrange.last

    net.inet.ip.portrange.first: 49152
    net.inet.ip.portrange.last: 65535



    这是 16,383 临时范围内的可用端口。

    要查看所有网络参数,您可以执行:
    sysctl net.inet.tcp
    您可以更改 TIME_WAIT 值,但对于您的高压力应用程序,它只会降低您的减速等待的阈值。

    您可以使用 netstat -an 查看打开的连接数。如果您打开和关闭大量连接,套接字可能会卡在 TIME_WAIT 状态。在某些地方这是不可避免的,但如果是这种情况,您可能需要考虑是否需要连接池。

    如果 TIME_WAIT 是问题,您可以调整系统设置。您可以设置 net.ipv4.tcp_tw_reuse / net.ipv4.tcp_tw_recycle加快连接周转速度。

    一个快速测试是切换到另一个界面并重试。如果您使用的是 localhost,然后遇到速度变慢的情况,您可以在另一个接口(interface)上切换到您的外部 IP,您应该像 gangbusters 一样运行,直到再次达到限制。

    这不是您使用的语言的问题,而是基于套接字的网络使用的问题。

    关于c - 为什么在 ~16370 个套接字连接后会有长时间的停顿?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53059831/

    26 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com