c++ - 如何将 UDP socket recv 缓冲区大小增加到 Linux 程序的最大值?
问题描述
我正在尝试增加 UDP 套接字的接收缓冲区大小,但最终大小似乎无法预测:
LOG_INFO("UDP echo server default receive buffer size : " << rcv_buf << " bytes");
// increase default buffer sizes
rcv_buf *= 3;
LOG_INFO("trying to increase receive buffer size to : " << rcv_buf << " bytes");
if (!SockWrap::set_recv_buf_size(m_handle, sizeof(m_sockaddr_in), rcv_buf))
LOG_ERR("unable to set new receive buffer size");
// checking the new size after possible modifications if any
rcv_buf = SockWrap::recv_buf(m_handle, sizeof(m_sockaddr_in));
if (rcv_buf == -1) {
LOG_ERR("unable to read UDP echo server receive buffer size after modification");
} else {
LOG_INFO("UDP echo server new receive buffer size : " << rcv_buf << " bytes");
}
包装函数是:
bool SockWrap::set_recv_buf_size(int fd, socklen_t len, int size)
{
// SO_RCVBUF option is an integer
int n = setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &size, len);
if (n == -1) {
LOG_ERR("setsockopt : " << strerror(errno));
return false;
}
return true;
}
和
int SockWrap::recv_buf(int fd, socklen_t len)
{
// SO_RCVBUF option is an integer
int optval;
if (getsockopt(fd, SOL_SOCKET, SO_RCVBUF, &optval, &len) == -1) {
LOG_ERR("getsockopt : " << strerror(errno));
return -1;
} else
return optval;
}
输出 :
UDP echo server default receive buffer size : 212992 bytes
trying to increase receive buffer size to : 638976 bytes
UDP echo server new receive buffer size : 425984 bytes
我已经检查了我的系统的限制/proc/sys/net/ipv4
:
cat udp_rmem_min
4096
cat udp_mem
186162 248216 372324
并且在/proc/sys/net/core
cat rmem_max
212992
cat rmem_default
212992
所以第一个输出看起来很清楚,默认的 recv 缓冲区值是 212992 字节,由rmem_default
.
但是后来尺寸增加了,而且比我想要的大得多,rmem_max
但仍然不是我想要的。
这个最终值(425984 字节)来自哪里?
这个值是最大值吗?它是否取决于内核当前使用了多少内存?
编辑 :
根据答案,我测试了其他值,似乎甚至可以设置rmem_default
为大于rmem_max
:
echo 500000 > /proc/sys/net/core/rmem_default
cat /proc/sys/net/core/rmem_default
500000
现在setsockopt
调用之前,getsockopt
返回(一如既往)rmem_default
,而不是rmem_default * 2
500000。
但是如果我使用setsockopt
将值设置为 500000 则getsocktop
返回rmem_max * 2
425984。
因此,似乎使用/proc
interface 可以比setsockopt
.
rmem_max
if rmem_default
can be greater的目的是什么?
/* from kernel 5.10.63 net/core/sock.c */
case SO_RCVBUF:
/* Don't error on this BSD doesn't and if you think
* about it this is right. Otherwise apps have to
* play 'guess the biggest size' games. RCVBUF/SNDBUF
* are treated in BSD as hints
*/
__sock_set_rcvbuf(sk, min_t(u32, val, sysctl_rmem_max));
break;
和
static void __sock_set_rcvbuf(struct sock *sk, int val)
{
/* Ensure val * 2 fits into an int, to prevent max_t() from treating it
* as a negative value.
*/
val = min_t(int, val, INT_MAX / 2);
sk->sk_userlocks |= SOCK_RCVBUF_LOCK;
/* We double it on the way in to account for "struct sk_buff" etc.
* overhead. Applications assume that the SO_RCVBUF setting they make
* will allow that much actual data to be received on that socket.
*
* Applications are unaware that "struct sk_buff" and other overheads
* allocate from the receive buffer during socket buffer allocation.
*
* And after considering the possible alternatives, returning the value
* we actually used in getsockopt is the most desirable behavior.
*/
WRITE_ONCE(sk->sk_rcvbuf, max_t(int, val * 2, SOCK_MIN_RCVBUF));
}
但也许这个编辑应该是另一个(相关的)问题。
谢谢你。
解决方案
根据文档:
SO_RCVBUF
设置或获取最大套接字接收缓冲区(以字节为单位)。当使用setsockopt(2)设置该值时,内核将该值加倍(以便为簿记开销留出空间) ,并且该加倍值由getsockopt(2)返回。默认值由/proc/sys/net/core/rmem_default
文件设置,最大允许值由/proc/sys/net/core/rmem_max
文件设置。此选项的最小(加倍)值为 256。
所以,在你的情况下,rmem_max
是212992
,所以你的输入从减少638976
到212992
,然后setsockopt()
加倍,因此425984
。
推荐阅读
- pyinstaller - pyinstaller3.4 python3.5 --key=key-string 导致的问题
- vb.net - Hasmorepages 属性失败
- c# - 当输入/输出编码为 Encoding.UTF8 时,Console.ReadLine 为 unicode 输入返回空字符串?
- dart - 两个小部件一个重新渲染另一个不
- java - Protoc Java 插件的依赖项?
- python - 作为变量打开的文件未在其他方法中定义
- typescript - 未找到 NgbModalBackdrop 的组件工厂。你把它添加到@NgModule.entryComponents 了吗?即使我将 enteryComponent 添加到我的模块
- sml - SML中的过滤功能
- git - 如何使用 Dep 将一组通用的个人 makefile 导入我的 go 项目,避免子模块?
- sql - SQL server 2012 - 转换销售订单行数据以进行 knime 购物篮分析