Linux系统下UDP发送缓冲区的正确配置方法
问题描述
- 在Ubuntu 22.04.1 LTS环境下的C++程序中,发送大量小于1KB的UDP消息时,多数请求耗时低于300毫秒,但每约150次发送会出现一次3秒的延迟;该现象仅在WiFi网络中出现,以太网环境下无异常。
- 尝试调整Linux系统参数
net.core.rmem_max和net.core.rmem_default至26214400,未对程序产生任何影响。 - 随后在代码中调用
setsockopt(sock_fd, SOL_SOCKET, SO_SNDBUF, &size, size_len)设置发送缓冲区大小为26214400,延迟问题得以解决,但通过getsockopt查询发现实际生效的缓冲区大小为5228800。 - 咨询:Linux下正确增大UDP发送缓冲区的方法是什么?
解决方案与细节解释
1. 纠正参数调整的错误方向
你之前修改的net.core.rmem_max和net.core.rmem_default是接收缓冲区的系统配置参数,和发送端延迟问题完全不相关,自然不会有效果。要调整UDP发送缓冲区,需要修改发送方向的系统参数:net.core.wmem_max(发送缓冲区最大上限)和net.core.wmem_default(默认发送缓冲区大小)。
2. 系统参数的正确调整方式
临时生效(重启系统后失效)
直接在终端执行以下命令:
sysctl -w net.core.wmem_max=26214400 sysctl -w net.core.wmem_default=26214400
永久生效(无需重启立即生效)
编辑/etc/sysctl.conf文件,添加或修改以下两行:
net.core.wmem_max=26214400 net.core.wmem_default=26214400
执行sysctl -p命令让配置立即生效。
3. 为什么代码设置的缓冲区大小和实际生效值不一致?
Linux内核会对应用层设置的SO_SNDBUF值做两层限制:
- 内核会为自身管理预留额外空间,实际分配的缓冲区大小会和应用层请求值有差异(通常是内核内部做了对齐或资源预留处理)。
- 如果你设置的
SO_SNDBUF值超过了net.core.wmem_max,内核会自动截断到wmem_max允许的最大值(你之前未调整wmem_max,所以实际生效的5228800就是当时系统允许的最大发送缓冲区,刚好能解决你的延迟问题)。
如果想要让实际生效值更接近你的预期,先把net.core.wmem_max调整到足够大的数值(比如设置为52428800),再在代码中设置SO_SNDBUF。
4. 代码层面的正确设置步骤
在UDP socket创建完成后、绑定/发送数据之前,调用setsockopt设置发送缓冲区,示例代码如下:
#include <sys/socket.h> #include <netinet/in.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> int main() { int sock_fd = socket(AF_INET, SOCK_DGRAM, 0); if (sock_fd < 0) { perror("socket创建失败"); exit(EXIT_FAILURE); } // 设置UDP发送缓冲区大小 int send_buf_size = 26214400; socklen_t size_len = sizeof(send_buf_size); if (setsockopt(sock_fd, SOL_SOCKET, SO_SNDBUF, &send_buf_size, size_len) < 0) { perror("设置SO_SNDBUF失败"); close(sock_fd); exit(EXIT_FAILURE); } // 验证实际生效的缓冲区大小 int actual_size; getsockopt(sock_fd, SOL_SOCKET, SO_SNDBUF, &actual_size, &size_len); printf("实际UDP发送缓冲区大小: %d 字节\n", actual_size); // 后续的socket绑定、发送逻辑... close(sock_fd); return 0; }
注意:必须在socket创建后立即设置缓冲区,不要等到绑定或发送数据后再操作,否则设置可能不生效。
5. WiFi环境下延迟的根源
WiFi属于共享无线介质,丢包率、传输稳定性远低于以太网。当UDP发送缓冲区满时,默认情况下sendto调用会阻塞,直到内核缓冲区有空闲空间。你之前的缓冲区太小,每发送约150个包就会填满缓冲区,导致阻塞等待;增大缓冲区后,能容纳更多待发送的数据包,避免了频繁的阻塞,从而消除了延迟。
内容的提问来源于stack exchange,提问作者immutableT
相关产品推荐
相关产品推荐

