UDP收发缓冲区设置不生效,十有八九是系统级上限在作祟。得先调大 /proc/sys/net/core/rmem_max 和 wmem_max,再通过 setsockopt 设置 socket 选项,而且必须在 bind() 之前调用,最后还得验证实际值——不然内核会悄悄截断,连个错误提示都不给。

UDP收发缓冲区为什么改了没生效
直接修改 setsockopt 的 SO_RCVBUF 或 SO_SNDBUF 却没有效果?大概率是撞上了系统级上限——/proc/sys/net/core/rmem_max 和 wmem_max。就算你在程序里传入了 32MB,只要超过这两个值,内核就会默默截断到最大值,连个错误提示都不给。
验证方法很简单,敲两行命令看看:
cat /proc/sys/net/core/rmem_max cat /proc/sys/net/core/wmem_max
常见默认值是 212992(约 208KB),对于高吞吐 UDP 场景来说,简直杯水车薪。所以必须先调整系统参数,再修改 socket 选项。
永久修改系统 UDP 缓冲区上限
编辑 /etc/sysctl.conf,追加三行(单位字节,比如设为 16MB):
net.core.rmem_max = 16777216 net.core.wmem_max = 16777216 net.core.rmem_default = 8388608
然后执行 sysctl -p 生效。注意:rmem_default 是新 socket 的默认接收缓冲区大小,不设它的话,即使 rmem_max 调高了,新 socket 仍沿用旧默认值(通常很小)。
千万别图省事用 /etc/rc.local 里 echo 的方式——那玩意儿依赖启动顺序,容易被 systemd 服务覆盖掉,重启后很可能失效。
程序中正确设置 socket 缓冲区
在 bind() 之前调用 setsockopt,且传入的值不能超过 rmem_max:
int size = 8388608; // 必须 ≤ rmem_max
if (setsockopt(sockfd, SOL_SOCKET, SO_RCVBUF, &size, sizeof(size)) == -1) {
perror("setsockopt SO_RCVBUF");
}
- 调用后建议用
getsockopt检查实际生效值,别以为设了就完事——内核会悄悄对齐到页倍数,比如 4KB。 SO_RCVBUF影响接收队列长度,丢包前能暂存更多数据;SO_SNDBUF影响发送端排队能力,对突发发包有帮助。- 如果用的是
AF_UNIX或 TCP,这套逻辑不适用——TCP 有滑动窗口自适应,UDP 才真靠这个硬扛丢包。
XFS 文件系统下调整挂载点容量时别碰缓冲区
“挂载缓冲区”这个说法其实不太标准——有人把 mount 时的 buffer 选项或文件系统缓存误当作 UDP 缓冲区。CentOS 7 的 XFS 默认使用 write-back 缓存,和网络缓冲区完全是两码事。
如果你真正想调整的是磁盘 I/O 缓存行为,那是 /proc/sys/vm/dirty_* 参数的事;如果是扩容 /home 或 / 分区,要用 lvextend + xfs_growfs,和 rmem_max 没半毛钱关系。
混淆这两类“缓冲区”,会导致改了一堆 sysctl 却发现磁盘写入变慢,或者拼命调 dirty_ratio 却解决不了 UDP 丢包——它们压根不在一个子系统里。
