You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何TCP套接字SO_SNDBUF默认值为wmem_default的1/13且最小值异常?

套接字发送缓冲区的两个疑问:默认值不匹配、最小缓冲区不符合手册描述

问题背景与现象

我在做套接字练习时写了这段代码:

const int socketfd = socket(AF_INET, SOCK_STREAM, 0);

int tcprcvbuf;
socklen_t tcprcvbuflen = sizeof(tcprcvbuf);
  
getsockopt(socketfd, SOL_SOCKET, SO_SNDBUF, &tcprcvbuf, &tcprcvbuflen);
printf("Default send buffer (TCP): %d\n", tcprcvbuf);

输出结果为:

Default send buffer (TCP): 16384

但执行命令cat /proc/sys/net/core/wmem_default得到的结果是212992,是前者的13倍。

另外,根据socket(7)手册的描述:

SO_SNDBUF
设置或获取套接字最大发送缓冲区字节数。使用setsockopt(2)设置时,内核会将该值翻倍(预留记账开销空间),getsockopt(2)会返回翻倍后的值。默认值由/proc/sys/net/core/wmem_default文件设置,最大值由/proc/sys/net/core/wmem_max文件设置。该选项的最小(翻倍后)值为2048

我测试setsockopt时发现:设置任何小于2304的值,getsockopt都会返回4608(符合翻倍逻辑);设置大于2304的值则返回预期的翻倍值。但手册明确说最小翻倍后的值是2048,这明显矛盾,请问我忽略了什么要点?


问题解答

关于默认send buffer与wmem_default不匹配的问题

这是因为TCP套接字的默认缓冲区大小会被TCP层额外调整,不会直接沿用net/core/wmem_default的全局值。

全局的wmem_default是所有套接字类型(包括UDP、RAW等)的基础默认值,但TCP有独立的缓冲区初始化逻辑:内核会根据系统内存大小、TCP拥塞控制策略等,给新建的TCP套接字设置更保守的初始缓冲区(比如你看到的16384),而非直接使用全局wmem_default。只有当你显式调用setsockopt设置SO_SNDBUF时,才会以wmem_default和wmem_max作为约束边界。

关于最小缓冲区不符合手册描述的问题

手册里的“最小(翻倍后)值为2048”是套接字层的内核最低下限,但实际还有TCP层的额外限制:TCP要求每个套接字的发送缓冲区至少能容纳一个完整的TCP分段(segment)。

在多数系统中,TCP最小分段大小加上TCP头部、IP头部的开销,换算后对应的缓冲区需求刚好是4608(即你看到的2304翻倍后的值)。所以当你设置的SO_SNDBUF值过小,导致翻倍后低于TCP要求的最小值时,内核会自动将缓冲区提升到TCP允许的最小尺寸4608——这相当于TCP层的要求覆盖了套接字层的2048下限,实际生效的是两者中的较大值。

内容的提问来源于stack exchange,提问作者Lady Idiot

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.24 23:10:55