美文网首页
linux下SO_RCVBUF的默认值

linux下SO_RCVBUF的默认值

作者: 叶迎宪 | 来源:发表于2022-06-24 20:48 被阅读0次

网上的说法,SO_RCVBUF的默认值是 /proc/sys/net/core/rmem_default,能设置的最大值是/proc/sys/net/core/rmem_max。但是也有说法,对于tcp,值会受到 /proc/sys/net/ipv4/tcp_rmem 的影响。自己写个程序实测一下。先读一下CentOS7下各参数的默认值

[root@localhost ~]# cat /proc/sys/net/core/rmem_default
212992
[root@localhost ~]# cat /proc/sys/net/core/rmem_max
212992
[root@localhost ~]# cat /proc/sys/net/ipv4/tcp_rmem
4096 87380 6291456

跑一个最简单的tcp client测试程序

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

int main(int argc,char *argv[]) {
    int sockfd,sendbytes;
    struct sockaddr_in serv_addr;//需要连接的服务器地址信息

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

    //填充服务器地址信息
    serv_addr.sin_family        = AF_INET; //网络层的IP协议: IPV4
    serv_addr.sin_port          = htons(8080); //传输层的端口号
    serv_addr.sin_addr.s_addr   = inet_addr("192.168.1.77"); //网络层的IP地址: 实际的服务器IP地址
    bzero(&(serv_addr.sin_zero),8); //保留的8字节置零

    if((connect(sockfd,(struct sockaddr *)&serv_addr,sizeof(struct sockaddr))) < 0) {
        perror("connect failed!");
        exit(1);
    }

    printf("connect successful! \n");

    int rcv_bufsize = 0;
    int len = sizeof(int);
    int ret = getsockopt(sockfd, SOL_SOCKET, SO_RCVBUF, &rcv_bufsize, &len);

    printf("recv_buf_size = %d\n", rcv_bufsize);

    close(sockfd);
}

跑一下,输出为
recv_buf_size = 367360

很明显,大于rmem_default、rmem_max,也大于tcp_rmem[1]。试着修改一下这几个参数,看程序输出有啥变化
echo 4000000 > /proc/sys/net/core/rmem_default
echo 4000000 > /proc/sys/net/core/rmem_max

recv_buf_size = 367360
没有变化,说明对于tcp,rmem_default、rmem_max是不起决定性作用的。

echo "4096 47380 6291456" > /proc/sys/net/ipv4/tcp_rmem
recv_buf_size = 367360
echo "4096 87380 87380" > /proc/sys/net/ipv4/tcp_rmem
recv_buf_size = 87380

似乎说明tcp_rmem[1]对于接受缓冲区默认值不起作用,但是tcp_rmem[2]对最大值限制是起作用的。要注意到,上面的测试程序中,getsockopt是发生在connect成功后的。如果把getsockopt放在socket建立后,connect调用前呢?

echo "4096 47380 6291456" > /proc/sys/net/ipv4/tcp_rmem
recv_buf_size = 47380
echo "4096 87380 6291456" > /proc/sys/net/ipv4/tcp_rmem
recv_buf_size = 87380

这时候,就跟tcp_rmem[1]完全一致了。

接着试验setsockopt。先设置SO_RCVBUF为110241024,然后再用getsockopt读出来,看看什么结果
recv_buf_size = 425984

明显大小被限制了。这个限制值看起来跟tcp_rmem[3]三个值都没关系,但正好是 /proc/sys/net/core/rmem_max 的两倍。

https://man7.org/linux/man-pages/man7/tcp.7.html

Note that TCP actually allocates twice the size of the
buffer requested in the setsockopt(2) call, and so a succeeding
getsockopt(2) call will not return the same size of buffer as
requested in the setsockopt(2) call

结论

tcp连接建立时,SO_RCVBUF初始化为tcp_rmem[1]。随着tcp握手及通信,SO_RCVBUF是会动态调整的,调整的范围不受rmem_max限制,只受tcp_rmem[2]的限制。但是如果手动通过setsockopt设置接收缓冲区大小,则自动调整接收缓冲区大小的机制失效,而且setsockopt是否成功会受到rmem_max的限制。

https://stackoverflow.com/questions/31546835/tcp-receiving-window-size-higher-than-net-core-rmem-max/35438236#comment58576526_35438236

相关文章

网友评论

      本文标题:linux下SO_RCVBUF的默认值

      本文链接:https://www.haomeiwen.com/subject/zhkbvrtx.html