网上的说法,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的限制。
网友评论