用netstat -tunap查看每个socket的Recv-Q/Send-Q:Recv-Q非0说明应用读取慢导致接收缓冲区堆积,Send-Q非0表明发送缓冲区卡住,可能因对端ACK丢失、网络拥塞或断连;二者均为瞬时排队字节数,非配置值。

怎么用 netstat 看每个 socket 的 Recv-Q / Send-Q
Recv-Q 和 Send-Q 是 netstat 输出里最直接反映套接字当前缓冲区占用的字段,但要注意:它们不是“配置值”,而是“瞬时排队长度”——即内核协议栈里尚未被应用读走(Recv-Q)或尚未发出去(Send-Q)的数据字节数。
执行 netstat -tunap(需 root 权限看 PID),重点关注这两列:
-
Recv-Q非 0:说明应用读得太慢,数据在接收缓冲区堆积;持续高值可能丢包或触发 TCP 慢启动回退 -
Send-Q非 0:说明对端接收窗口小、网络拥塞或本端写太快,数据卡在发送缓冲区;若长期不降,可能是对端断连或 ACK 丢失
注意:netstat 不显示缓冲区上限或默认值,只反映实时积压。它无法区分是 TCP 还是 UDP 套接字的底层缓冲策略,仅展示协议栈已排队的数据量。
怎么查某个 socket 的实际 SO_RCVBUF / SO_SNDBUF 设置值
要用 getsockopt 才能拿到进程级设置的缓冲区大小,因为 netstat 只显示排队量,不暴露 socket 层配置。
典型做法是写一段 C 或 Python 小程序,用 getsockopt 获取当前 socket 的 SO_RCVBUF 和 SO_SNDBUF:
int rcvbuf, sndbuf; socklen_t len = sizeof(rcvbuf); getsockopt(sockfd, SOL_SOCKET, SO_RCVBUF, &rcvbuf, &len); // 实际值可能被内核翻倍 getsockopt(sockfd, SOL_SOCKET, SO_SNDBUF, &sndbuf, &len);
关键点:
- 返回值常比你
setsockopt时设的值大一倍——内核为管理开销额外分配空间,这是正常行为 - 如果返回值等于
/proc/sys/net/core/rmem_max或wmem_max,说明你之前调用setsockopt时已触及系统上限 - 没显式调用
setsockopt的 socket,会继承net.core.rmem_default/wmem_default
怎么确认系统级缓冲区参数是否生效
Linux 有两层缓冲控制:通用套接字层(net.core.*)和 TCP 协议栈层(net.ipv4.tcp_*)。单看某一层容易误判。
必须同时检查:
-
sysctl net.core.rmem_max net.core.wmem_max—— 所有 socket 的硬上限,TCP 缓冲不能超这个值 -
sysctl net.ipv4.tcp_rmem net.ipv4.tcp_wmem—— TCP socket 的三元组(min default max),真正决定连接行为
常见坑:
- 改了
tcp_rmem但忘了同步调大rmem_max,内核会静默截断到rmem_max值 - UDP socket 完全不认
tcp_rmem,只受net.core.rmem_default和rmem_max控制 - 修改后必须运行
sysctl --system或sysctl -p加载,否则只在内存生效,重启丢失
为什么 /proc/net/snmp 里的 TcpInSegs/TcpOutSegs 不能反推缓冲区大小
有人想从网络统计计数器倒推缓冲区配置,这是行不通的。
/proc/net/snmp 中的 TcpInSegs、TcpOutSegs 是 TCP 段收发总数,和缓冲区大小无直接换算关系。它们反映的是流量吞吐量,不是内存占用。
真正和缓冲区相关的统计在:
-
/proc/net/sockstat:汇总各协议 socket 数量、内存总用量(sockets: used和TCPSockets:行) -
/proc/net/snmp中的TcpRcvQFull:接收队列满导致丢包次数——这才是缓冲区过小的直接证据
别指望靠流量数字猜配置,该查 proc 就查 proc,该跑 getsockopt 就跑 getsockopt。


















