当前位置 主页 > 服务器问题 > Linux/apache问题 >

    如何测试Linux下tcp最大连接数限制详解

    栏目:Linux/apache问题 时间:2019-11-05 23:50

    前言

    关于TCP服务器最大并发连接数有一种误解就是“因为端口号上限为65535,所以TCP服务器理论上的可承载的最大并发连接数也是65535”。

    先说结论:对于TCP服务端进程来说,他可以同时连接的客户端数量并不受限于可用端口号。并发连接数受限于linux可打开文件数,这个数是可以配置的,可以非常大,所以实际上受限于系统性能。

    现在做服务器开发不加上高并发根本没脸出门,所以为了以后吹水被别人怼“天天提高并发,你自己实现的最高并发是多少”的时候能义正言辞的怼回去,趁着元旦在家没事决定自己写个demo搞一搞。

    这个测试主要是想搞明白Linux下哪些参数配置限制了连接数的最大值,上限是多少。

    一、先说下demo的思路:

    服务端用epoll实现,就是简简单单的接收连接,然后客户端用go的goroutine,每个goroutine就是简单的建立连接,然后什么也不做。

    上代码:

    server:

    /*
     * g++ -o test_epoll ./test_epoll.c
     */
    #include <unistd.h>
    #include <sys/types.h>
    #include <sys/socket.h>
    #include <sys/epoll.h>
    #include <netinet/in.h>
    #include <arpa/inet.h>
    
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <errno.h>
    
    int SetReuseAddr(int fd)
    {
     int optval = 1;
     socklen_t optlen = sizeof(optval);
     return setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &optval, optlen);
    }
    
    int main()
    {
     int fd = socket(AF_INET, SOCK_STREAM, 0);
     int iRet = SetReuseAddr(fd);
     if (iRet != 0)
     {
     printf("setsockopt for SO_REUSEADDR failed, error:%s\n", strerror(iRet));
     return iRet;
     }
    
     struct sockaddr_in addr;
     memset(&addr, 0, sizeof(addr));
     addr.sin_family = AF_INET;
     addr.sin_port = htons(8080);
     addr.sin_addr.s_addr = INADDR_ANY;
     if (bind(fd, (struct sockaddr*)&addr, sizeof(addr)) == -1)
     {
     printf("bind failed, error:%s\n", strerror(errno));
     return errno;
     }
    
     if (listen(fd, 5) == -1)
     {
     printf("listen failed, error:%s\n", strerror(errno));
     return errno;
     }
     printf("Listening on 8080...\n");
    
     int epfd = epoll_create(102400);
     struct epoll_event event;
     event.events = EPOLLIN;
     event.data.fd = fd;
     epoll_ctl(epfd, EPOLL_CTL_ADD, fd, &event);
    
     struct epoll_event revents[102400];
     int iOnline = 0;
     while (1)
     {
     int num = epoll_wait(epfd, revents, 102400, 60 * 1000);
     printf("epoll_wait return %d\n", num);
     if (num > 0)
     {
      for (int i = 0; i < num; i++)
      {
      if (revents[i].data.fd == fd)
      {
       int client;
       struct sockaddr_in cli_addr;
       socklen_t cli_addr_len = sizeof(cli_addr);
       client = accept(fd, (struct sockaddr*)&cli_addr, &cli_addr_len);
       if (client == -1)
       {
       printf("accept failed, error:%s\n", strerror(errno));
       if (errno == EMFILE)
       {
        printf("per-process limit reached\n");
        exit(errno);
       }
       if (errno == ENFILE)
       {
        printf("system-wide limit reached\n");
        exit(errno);
       }
       continue;
       }
    
       iOnline++;
       printf("Receive a new connection from %s:%d\n", inet_ntoa(cli_addr.sin_addr), cli_addr.sin_port);
       event.events = EPOLLIN;
       event.data.fd = client;
       epoll_ctl(epfd, EPOLL_CTL_ADD, fd, &event);
      }
      }
     }
     printf("Online number:%d\n", iOnline);
     }
    
     return 0;
    }