Linux ss -m / -o / -p 的 socket 内存 / timer / process 信息查看实践

1次阅读

ss -m 的 mem: 显示内核为 socket 分配的收发缓冲区当前占用字节数,非上限值;rmem 是接收队列已排队数据量,wmem 是发送队列未处理数据量,udp 的 wmem 恒为 0。

Linux ss -m / -o / -p 的 socket 内存 / timer / process 信息查看实践

ss -m 看 socket 内存时,mem: 里那些数字到底对应啥

直接看 ss -m 输出里的 mem: 行,容易误以为是“当前占用内存”,其实它展示的是内核为该 socket 分配的各层缓冲区大小(单位字节),不是 RSS 或进程实际内存开销。

常见错误现象:发现某个连接 mem: rmem:131072 wmem:131072,就以为占了 256KB 内存——但这是收发缓冲区上限(sk->sk_rcvbuf/sk->sk_sndbuf),实际只在有数据排队时才真实占用;空闲连接几乎不耗内存。

  • rmem 是接收队列已排队字节数(不是上限),rcv_space 才是当前通告窗口大小
  • wmem 是发送队列中尚未被协议处理的数据量(比如还在 sk_write_queue 里),不含已交给网卡但未确认的部分
  • UDP socket 的 wmem 永远是 0,因为无重传队列;TCP 的 wmem 高可能意味着对端接收慢或丢包
  • ss -m state established 过滤后,再按 wmem 排序:ss -m state established | sort -k8,8n(第8字段通常是 wmem)

ss -o 显示 timer 信息时,“on” 和 “off” 到底表示什么状态

ss -o 的 timer 字段(如 timer:(keepalive,15min,0))不是开关状态,而是描述该 socket 当前启用的定时器类型和剩余时间。所谓 “on/off” 是内核输出的简写,on 表示定时器已启动并计时中,off 表示未激活(比如刚建连还没到 keepalive 起始时间)。

容易踩的坑:看到 timer:(on,15min,0) 就以为 keepalive 正在发包——其实括号里第三个数字是重试次数,0 表示尚未触发超时重试;只有变成 (on,15min,1) 才说明第一次重传已失败。

  • TCP 常见 timer 类型:keepalive(保活)、timewait(TIME_WAIT 倒计时)、persist(零窗口探测)、retrans(重传)
  • ss -o state time-wait 会显示 timer:(timewait,sec:30),这个 30 秒是内核 tcp_fin_timeout 值,不是固定 2MSL
  • UDP socket 永远不会显示 timer,哪怕绑定了 SO_RCVTIMEO —— 因为超时是用户态控制的,内核 socket 层无定时器

ss -p 需要 root 权限才能显示进程名,但普通用户也能绕过部分限制

ss -p 默认要求 CAP_NET_ADMIN 或 root,否则报错 Permission denied。这不是设计缺陷,而是因为读取 /proc/[pid]/fd/ 下的 socket 符号链接需要目标进程的 ptrace 权限(由 /proc/sys/kernel/yama/ptrace_scope 控制)。

非 root 用户仍有办法获取部分信息:

  • 如果目标进程是自己启动的(UID 匹配),ss -p 可以正常显示进程名,无需 root
  • ss -tuln 先拿到监听端口和 inode,再手动查 lsof -i :端口号(需安装 lsof,且依赖 /proc 权限)
  • 检查 /proc/net/{tcp,tcp6,udp,udp6} 中的 inode 列,然后遍历 /proc/[0-9]*/fd/ 找符号链接指向 socket:[inode] —— 但普通用户只能遍历自己进程的 fd 目录
  • systemd 系统下,sudo ss -tulnpsudo netstat -tulpn 更快,因为不依赖 /proc/net 的文本解析,直接读取内核 sock_diag 接口

混用 -m/-o/-p 时,字段顺序和兼容性要注意

ss -mop 看起来方便,但不同内核版本输出字段数不一致:4.15+ 内核在 -m 后会多出 ino(inode 号)字段,而 -p 附加的进程信息会插在最后,导致列偏移错乱。用 awk 或 cut 提取字段时极易出错。

真实使用场景中,更稳妥的做法是分步查,而不是参数:

  • 先用 ss -tuln state established | head -20 定位可疑连接
  • 记下其 inode(最后一列),再单独查:ss -m -o -i "inode:123456"(注意引号和空格)
  • 想关联进程?用 ls -l /proc/*/fd/ 2>/dev/NULL | grep 'socket:[123456]',比 -p 更可靠
  • centos 7(内核 3.10)不支持 -o 的完整 timer 显示,会输出 timer:(off) 即使 keepalive 已启用——得看 /proc/sys/net/ipv4/tcp_keepalive_* 配置是否生效

最常被忽略的一点:socket 的内存、timer、进程三类信息来自内核不同子系统(sock, timer, task_struct),ss 是一次性发起多个 netlink 查询再拼装结果,中间若有进程退出或连接关闭,可能看到 “内存值正常但进程已不存在” 的情况——这不是 bug,是竞态窗口内的正常现象。

text=ZqhQzanResources