linux下SO_RCVBUF的默认值
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了linux下SO_RCVBUF的默认值相关的知识,希望对你有一定的参考价值。
参考技术A 网上的说法,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测试程序
跑一下,输出为
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为1 1024 1024,然后再用getsockopt读出来,看看什么结果
recv_buf_size = 425984
明显大小被限制了。这个限制值看起来跟tcp_rmem[3]三个值都没关系,但正好是 /proc/sys/net/core/rmem_max 的两倍。
https://man7.org/linux/man-pages/man7/tcp.7.html
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
即使对于“pktcount * pktsize”< SO_RCVBUF,linux socket recv 缓冲区数据包也会丢失
【中文标题】即使对于“pktcount * pktsize”< SO_RCVBUF,linux socket recv 缓冲区数据包也会丢失【英文标题】:linux socket recv buffer packet drops even for "pktcount * pktsize" < SO_RCVBUF 【发布时间】:2013-03-29 16:09:00 【问题描述】:我在 C 程序中向 250 个节点发送 icmp echo。 套接字是这样创建的
sfd = socket(PF_INET, SOCK_RAW, IPPROTO_ICMP);
我有getsockopt SO_RCVBUF :262142 .i.e 262KB 由于一个数据包需要84字节(包括IP,100字节在线),所以rcv缓冲区应该能够容纳 262142/84 = 3120 个数据包
sysctl parameters (defaults)
net.core.rmem_max = 131071
net.core.rmem_default = 113664
但有 10 多滴。
我正在发送所有回显请求,然后使用 recvfrom() 获取数据包。 很明显,回复数据包在套接字的 rcv 缓冲区中累积, 但是 rcv 缓冲区足够大,可以容纳 3120 个数据包。
数据包在接收主机上正确显示。
当我设置时:
sysctl -w net.core.rmem_max=1048576
and SO_RCVBUF to 2MB, the drops were 0.
为什么会这样?
活动中的队列很少。
-
网卡环形缓冲区。
nic 到内核队列
每个套接字 rcv 缓冲区
我猜 net.core.rmem_max 只会改变每个套接字 rcv 缓冲区。
任何指向正确方向的链接。
Platform Linux suse10/x86
网卡:英特尔公司 PRO/无线 2200BG
--添加更多
我禁用了上述无线接口并开始使用有线接口 以太网控制器:Broadcom Corporation NetXtreme BCM5705M_2 千兆以太网(rev 03) 情况发生了重大变化。
net.core.netdev_budget = 300
net.core.netdev_max_backlog = 1000
net.core.rmem_max = 131071
net.core.wmem_max = 131071
getsockopt SO_RCVBUF :262142
getsockopt SO_SNDBUF :262142
# ethtool -g eth1
Current hardware settings:
RX: 200
TX: 200
#
eth1 txqueuelen:1000
现在每 250 个数据包 0 丢包,每 1000 个包大约 170 个丢包 使用 ethtool -G 将 rx,tx 从默认值 200 更改为无效。
然后我更改了每个套接字 rcv 缓冲区的最大值
sysctl -w net.core.rmem_max=1024000
这允许每 6000 次掉落 0 次 每 7000 滴 500 滴
进一步增加 per-socket-rcv-buffer-max
sysctl -w net.core.rmem_max=2048000
每 7000 个数据包 0 丢包
有线网络给出了更加一致和合作的结果。
但问题仍然悬而未决 当 262142 字节缓冲区可以容纳 3000 个大小为 84 的数据包(带有 IP 标头)时,为什么会在 1000 个数据包时发生丢包。 即使在线数据包最大为 100 字节,262142 也可以容纳 2600 个数据包。
ethereal 大部分时间都能够获取数据包,并且 ifconfig 计数器显示没有丢包,因此这是 nic 驱动程序将数据包提供给内核之后发生的事情。
ethereal 也丢失了一些数据包,但这种情况较少发生。
只改变上面的这些
sysctl -w net.core.rmem_max=1024000
下降 96/1000 掉落 0/6000
下降 500/7000
sysctl -w net.core.rmem_max=2048000
下降 0/7000
sysctl -w net.core.rmem_max=512000
sysctl -w net.core.netdev_max_backlog=3000
下降 0/3000
sysctl -w net.core.rmem_max=256000
sysctl -w net.core.netdev_max_backlog=3000
下降 1400/3000
hold = 2 * 1024 * 1024;
setsockopt(sfd, SOL_SOCKET, SO_RCVBUF, (char *)&hold, sizeof(hold));
for(;;)
...
if(recvfrom(sfd,(char *)packet, packlen, 0, (struct sockaddr *)&from, &fromlen)) < 0)
rcvcount++;
process_packet(packet,packlen);
【问题讨论】:
【参考方案1】:(从 nntp:comp.os.linux.networking 转发我的答案)
以下代码回答了我的问题。
http://lxr.linux.no/#linux+v3.8.7/net/core/sock.c#L689
708set_rcvbuf:
709 sk->sk_userlocks |= SOCK_RCVBUF_LOCK;
710 /*
711 * We double it on the way in to account for
712 * "struct sk_buff" etc. overhead. Applications
713 * assume that the SO_RCVBUF setting they make will
714 * allow that much actual data to be received on that
715 * socket.
716 *
717 * Applications are unaware that "struct sk_buff" and
718 * other overheads allocate from the receive buffer
719 * during socket buffer allocation.
720 *
721 * And after considering the possible alternatives,
722 * returning the value we actually used in getsockopt
723 * is the most desirable behavior.
724 */
725 sk->sk_rcvbuf = max_t(u32, val * 2, SOCK_MIN_RCVBUF);
726 break;
由于我的数据包小于 100 字节数据,因此 sk_buff 开销会相当高。从视觉上看 sk_buff,对于 32 位系统,sk_buff 的大小似乎在 200 字节左右。
对于 100 字节在线数据包,这意味着只有三分之一的 rcvbuf 保存数据包数据。 2/3 是 sk_buff 开销。
所以对于 SO_RCVBUF :262142,
262142/3 = 87380 字节可用于数据包数据。
87380/100 = 873 是其中可以容纳的数据包数。
1000 - 873 = 1000 人中有 127 人被丢弃。
我得到的是170,与预期相差不远。
以下章节/书籍真的很有帮助。
[1] Christian Benvenuti 了解 Linux 网络内部结构 第三部分:传输和接收
[2] Sreekrishnan Venkateswaran 的基本 Linux 设备驱动程序 第 15 章网络接口卡
苏林德【讨论】:
您是如何计算出接收缓冲区的三分之二用于 sk_buff 开销的?给定消息大小、接收缓冲区和一些网络设置,我能否计算出缓冲区中可以存储多少数据包?【参考方案2】:这是一个长镜头,但由于您没有显示完整的代码,它可能与防火墙有关。一些恶意软件变种使用 ICMP 数据包风暴,因此如果有防火墙软件正在运行,则可能会阻碍其运行。
【讨论】:
# iptables -L -n Chain INPUT (policy ACCEPT) target prot opt source destination Chain FORWARD (policy ACCEPT) target prot opt source destination Chain OUTPUT (policy ACCEPT) target prot opt source destination #跨度>以上是关于linux下SO_RCVBUF的默认值的主要内容,如果未能解决你的问题,请参考以下文章