• tcp网络编程性能优化点


    1、修改select recv缓存区大小

        char tmp[1024];
        AMS_WARN("  --clear socket buff...");
        while(1) {        
            ret = select(FD_SETSIZE, &fds, NULL, NULL, &timeout);
            if(ret == 0) {
                break;
            }
            if (recv(client_fd, tmp, 1024, 0 ) != 1024) {
                break;
            }
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    建议将tmp大小设置为65535,业务代码逻辑可能需要修改。

    2、应用程序级修改缓冲区大小

    • 可以在程序中动态地修改(通过setsockopt系统调用)持有的有效Socket的读写缓冲区大小。

    • 参考代码:

      int ret, sock, sock_buf_size;
      sock = socket( AF_INET, SOCK_STREAM, 0 );
      sock_buf_size = BDP;
      ret = setsockopt( sock, SOL_SOCKET, SO_SNDBUF,
                         (char *)&sock_buf_size, sizeof(sock_buf_size) );
      ret = setsockopt( sock, SOL_SOCKET, SO_RCVBUF,
                         (char *)&sock_buf_size, sizeof(sock_buf_size) );
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7

      参考文章:Socket缓冲区大小修改与系统设置

    3、端口复用

    • 端口复用reuseport原因:单线程listener,在处理高速率海量连接时,会成为瓶颈;

    • 参考文章:Linux3.9中 SO_REUSEPORT 对高并发服务器的改进

    • 配置修改参考: c/c++:端口复用(setsockopt)、io多路转接(select、 poll、epoll)

      调用setsockopt函数:

      #include <sys/types.h> 
      #include <sys/socket.h>
      // 设置套接字属性
      int setsockopt(int sockfd, int level, int optname, const void *optval, socklen_t optlen);
      	参数:
      	- sockfd: 要操作的文件描述符
      	- level: 级别 -> SOL_SOCKET (端口复用的级别)
              - optname: 端口复用的级别(二选一,随便选,对于端口复用都可以)
              	- SO_REUSEADDR
              	- SO_REUSEPORT
              - optval: 端口复用-> 对应的是整形数
              	- 1: 可以复用
              	- 0: 不能复用
              - optlen: optval参数对应的内存大小
       
      // 设置端口复用, 设置的时机: 服务器绑定端口之前, 设置端口复用。例如:
      setsockopt();
      bind();
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18

    4、内核参数修改

    • 具体参数含义参考文章:Linux内核 TCP/IP、Socket参数调优

    • 修改linux系统文件句柄限制

      执行echo -e "* soft nofile 40960 \n* hard nofile 65536" >> /etc/security/limits.conf 修改linux系统文件句柄限制

       cat /etc/security/limits.conf
      将在limits.conf中添加以下参数
      * soft   nofile   40960
      * hard   nofile   65536
      
      • 1
      • 2
      • 3
      • 4

      参数

      * 代表所有用户有效
      soft:软限制,超过会报warn
      hard:实际限制
      nofile:文件句柄参数
      number:最大文件句柄数
      
      • 1
      • 2
      • 3
      • 4
      • 5

      使用ulimit -n 查看open files 参数是否改变。

    • TCP/IP内核参数优化,建议参数如下:

      /etc/sysctl.conf添加以下代码,重启后永久生效

      net.core.rmem_default = 8388608
      net.core.rmem_max = 16777216
      net.core.wmem_default = 8388608
      net.core.wmem_max = 16777216
      net.core.netdev_max_backlog = 2000
      net.core.somaxconn = 2048
      net.core.optmem_max = 81920
      net.ipv4.tcp_mem = 131072  262144  524288
      net.ipv4.tcp_rmem = 8760  8388608  16777216
      net.ipv4.tcp_wmem = 8760  8388608  16777216
      net.ipv4.tcp_keepalive_time = 60
      net.ipv4.tcp_keepalive_probes = 3
      net.ipv4.tcp_keepalive_intvl = 20
      
      vm.overcommit_memory=1
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15

    5、设置TcpNodelay和TcpKeepAlive

    • TCPNoDelay和TCPkeepalive都是常用的TCP选项,前者的作用是禁用Nagle 算法6,避免连续发包出现延迟,这对编写低延迟网络服务很重要。后者的作用是定期探查TCP连接是否还存在。一般来说如果有应用层心跳的话,TCPkeepalive不是必需的。

    • TCPNoDelay设置参考代码:

      int sock, flag, ret;
      /* Create new stream socket */
      sock = socket( AF_INET, SOCK_STREAM, 0 );
      /* Disable the Nagle (TCP No Delay) algorithm */
      flag = 1;
      ret = setsockopt( sock, IPPROTO_TCP, TCP_NODELAY, (char *)&flag, sizeof(flag) );
      if (ret == -1) {
        printf("Couldn't setsockopt(TCP_NODELAY)\n");
        exit(-1);
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
    • TCPkeepalive内核中设置参考上面第4点,应用程序中设置参考如下:

      int keepAlive = 1; // 开启keepalive属性
      int keepIdle = 60; // 如该连接在60秒内没有任何数据往来,则进行探测 
      int keepInterval = 5; // 探测时发包的时间间隔为5 秒
      int keepCount = 3; // 探测尝试的次数.如果第1次探测包就收到响应了,则后2次的不再发.
      
      setsockopt(rs, SOL_SOCKET, SO_KEEPALIVE, (void *)&keepAlive, sizeof(keepAlive));
      setsockopt(rs, SOL_TCP, TCP_KEEPIDLE, (void*)&keepIdle, sizeof(keepIdle));
      setsockopt(rs, SOL_TCP, TCP_KEEPINTVL, (void *)&keepInterval, sizeof(keepInterval));
      setsockopt(rs, SOL_TCP, TCP_KEEPCNT, (void *)&keepCount, sizeof(keepCount));
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
    • 见《Linux多线程服务编程》8.9节

    6、使用std::vector作为数据缓冲区,具体请参考https://gitee.com/liudegui/finger_server/blob/master/common/Buffer.cpp

  • 相关阅读:
    springbook 注解笔记
    盘点国内主流数字孪生厂商!你了解几家?
    编程之美1 哈利波特买书问题
    maven 上传本地jar包到nexus
    国家网络安全周2023时间是什么时候?有什么特点?谁举办的?
    SpringCloud Feign实现微服务间的远程调用(黑马头条Day04)
    Codeforces暑期训练周报(7.21~7.27)
    06.Octave的介绍、安装与简单使用
    Spring——依赖注入
    通义千问, 文心一言, ChatGLM, GPT-4, Llama2, DevOps 能力评测
  • 原文地址:https://blog.csdn.net/stallion5632/article/details/125551127