ss 命令详解与参数实测(Ubuntu 22.04)

ss 逐参数实测详解:默认输出、-t/-u/-l/-n/-p/-a 基础过滤、-tuln 与 netstat 对照、-s 统计摘要、-m 套接字内存 skmem 解读、-o 计时器、-i 观测 cwnd 与 rtt、-e 查看 ino 与 uid、-4/-6 地址族、-x UNIX 域套接字、state 状态过滤与 dst/src/dport 表达式,含 -K 强制关连的权限受限实测记录,附 ss 与 netstat 映射表,全部回显在 Ubuntu 22.04(iproute2 5.15.0)实测通过。

Linux命令Linux系统UbuntuUbuntu 22.04命令行网络工具2026/10/16

ss 命令详解与参数实测(Ubuntu 22.04)

目标:全面掌握 ss 的每一个常用参数——默认输出、-t/-u/-l/-n/-p/-a 基础过滤、-tuln 排查标配、-s 统计摘要、-m 套接字内存、-o 计时器、-i TCP 内部信息(cwnd/rtt)、-e 详细信息(ino/uid)、-4/-6 地址族、-d DCCP、-x UNIX 域套接字,以及 state 状态过滤、dst/src/dport 地址过滤与 -K 强制关连的实测行为,附 ss 与 netstat 的对照与命令映射,全部命令与回显已在 Ubuntu 22.04(iproute2 5.15.0)实测通过。

一、环境信息

  • 操作系统:Ubuntu 22.04.5 LTS(x86_64)
  • ss 版本:iproute2 5.15.0(ss -V 实测),由 iproute2 软件包提供,Ubuntu 22.04 默认预装
  • ss 通过内核 netlink 套接字(NETLINK_SOCK_DIAG)取数,不走 /proc 伪文件,这是它与 netstat 的本质区别(见 3.18 节)
  • 测试数据目录:/root/demo/ss/(存放模拟连接用的 Python 辅助脚本)
  • 演示端口:18000(演示用 HTTP 服务)、7778(echo 收发对)、7779(-K 实验)、8080/18081/9996(地址族演示)、9998(UDP)

二、命令概览

2.1 语法与测试数据

ss(socket statistics)用于查看内核套接字统计,支持按状态、地址、端口在内核侧过滤,基本语法是:

ss [选项] [状态过滤] [地址过滤表达式]

本文延续 netstat 篇的实测方法,在 /root/demo/ss/ 准备辅助脚本,每个演示块自带数据准备与清理,可直接复制复现:

# /root/demo/ss/hold.py —— 建立 TCP 连接并保持指定秒数(制造 ESTABLISHED)
import socket, sys, time
port = int(sys.argv[1]); secs = int(sys.argv[2])
s = socket.create_connection(("127.0.0.1", port))
time.sleep(secs)
# /root/demo/ss/echo_server.py —— accept 后回显一次再挂住(连接有流量,供 -i/-m/-o 观测)
import socket, sys, time
port = int(sys.argv[1]); secs = int(sys.argv[2])
srv = socket.socket(); srv.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
srv.bind(("127.0.0.1", port)); srv.listen(1)
c, _ = srv.accept()
data = c.recv(65536)
c.sendall(b"ACK " + data[:20])
time.sleep(secs)
# /root/demo/ss/echo_client.py —— 客户端开启 keepalive、发送并接收一次后挂住
import socket, sys, time
port = int(sys.argv[1]); secs = int(sys.argv[2])
s = socket.create_connection(("127.0.0.1", port))
s.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1)
s.sendall(b"hello-ss-demo")
time.sleep(0.5)
s.recv(1024)
time.sleep(secs)
# /root/demo/ss/unix_server.py / unix_client.py —— UNIX 域套接字演示对
import socket, sys, time
path = sys.argv[1]; secs = int(sys.argv[2])
srv = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
srv.bind(path); srv.listen(1)
c, _ = srv.accept()
time.sleep(secs)

# unix_client.py
import socket, sys, time
path = sys.argv[1]; secs = int(sys.argv[2])
s = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
s.connect(path)
time.sleep(secs)

演示服务仍用 python3 -m http.server 18000 --bind 127.0.0.1 提供 LISTEN 态,hold.py 挂 ESTABLISHED 态,curl 短请求制造 TIME_WAIT 态。

2.2 --help 全量输出

ss --help 逐行照抄如下(注意末尾的 STATE-FILTER 语法正是后文 3.15 状态过滤的官方说明):

Usage: ss [ OPTIONS ]
       ss [ OPTIONS ] [ FILTER ]
   -h, --help          this message
   -V, --version       output version information
   -n, --numeric       don't resolve service names
   -r, --resolve       resolve host names
   -a, --all           display all sockets
   -l, --listening     display listening sockets
   -o, --options       show timer information
   -e, --extended      show detailed socket information
   -m, --memory        show socket memory usage
   -p, --processes     show process using socket
   -i, --info          show internal TCP information
       --tipcinfo      show internal tipc socket information
   -s, --summary       show socket usage summary
       --tos           show tos and priority information
       --cgroup        show cgroup information
   -b, --bpf           show bpf filter socket information
   -E, --events        continually display sockets as they are destroyed
   -Z, --context       display process SELinux security contexts
   -z, --contexts      display process and socket SELinux security contexts
   -N, --net           switch to the specified network namespace name

   -4, --ipv4          display only IP version 4 sockets
   -6, --ipv6          display only IP version 6 sockets
   -0, --packet        display PACKET sockets
   -t, --tcp           display only TCP sockets
   -M, --mptcp         display only MPTCP sockets
   -S, --sctp          display only SCTP sockets
   -u, --udp           display only UDP sockets
   -d, --dccp          display only DCCP sockets
   -w, --raw           display only RAW sockets
   -x, --unix          display only Unix domain sockets
       --tipc          display only TIPC sockets
       --vsock         display only vsock sockets
   -f, --family=FAMILY display sockets of type FAMILY
       FAMILY := {inet|inet6|link|unix|netlink|vsock|tipc|xdp|help}

   -K, --kill          forcibly close sockets, display what was closed
   -H, --no-header     Suppress header line
   -O, --oneline       socket's data printed on a single line
       --inet-sockopt  show various inet socket options

   -A, --query=QUERY, --socket=QUERY
       QUERY := {all|inet|tcp|mptcp|udp|raw|unix|unix_dgram|unix_stream|unix_seqpacket|packet|netlink|vsock_stream|vsock_dgram|tipc}[,QUERY]

   -D, --diag=FILE     Dump raw information about TCP sockets to FILE
   -F, --filter=FILE   read filter information from FILE
       FILTER := [ state STATE-FILTER ] [ EXPRESSION ]
       STATE-FILTER := {all|connected|synchronized|bucket|big|TCP-STATES}
         TCP-STATES := {established|syn-sent|syn-recv|fin-wait-{1,2}|time-wait|closed|close-wait|last-ack|listening|closing}
          connected := {established|syn-sent|syn-recv|fin-wait-{1,2}|time-wait|close-wait|last-ack|closing}
       synchronized := {established|syn-recv|fin-wait-{1,2}|time-wait|close-wait|last-ack|closing}
             bucket := {syn-recv|time-wait}
                big := {established|syn-sent|fin-wait-{1,2}|closed|close-wait|last-ack|listening|closing}

2.3 版本信息

ss -V
ss utility, iproute2-5.15.0

三、参数逐项实测

3.1 默认输出(已连接 TCP)

不带参数时 ss 只显示已连接的 inet 套接字。先起服务并挂一条保持连接:

python3 -m http.server 18000 --bind 127.0.0.1 >/dev/null 2>&1 &
python3 /root/demo/ss/hold.py 18000 60 >/dev/null 2>&1 &
ss | head -12
Netid State Recv-Q Send-Q Local Address:Port  Peer Address:Port Process
tcp   ESTAB 0      0          127.0.0.1:18000    127.0.0.1:38828       
tcp   ESTAB 0      0          127.0.0.1:38828    127.0.0.1:18000       

ss 的列结构与 netstat 不同,逐列说明:

列名含义
Netid套接字类型:tcp/udp/u_str(UNIX 流)/u_seq/nl(netlink)/p_raw 等,仅 -a 或含非 inet 视图时出现
StateTCP 状态,ss 用缩写(ESTAB/LISTEN/TIME-WAIT/CLOSE-WAIT),比 netstat 的全称短
Recv-Q / Send-Q与 netstat 同义:ESTAB 态为字节队列,LISTEN 态 Recv-Q 为待 accept 连接数、Send-Q 为 backlog 上限
Local Address:Port / Peer Address:Port本端与对端地址:端口
Process-p 时显示 users:(("进程名",pid=N,fd=M))

与 netstat 默认视图的两点差异(对照 netstat 篇 3.1 实测):ss 默认不显示 UNIX 域已连接套接字;ss 默认不做主机名反解(直接显示 127.0.0.1,netstat 显示 localhost),所以 ss 默认就很快。

3.2 -t / -u:协议过滤

-t 只看 TCP,输出格式与默认一致但去掉 Netid 列;-u 只看 UDP:

ss -t
State Recv-Q Send-Q Local Address:Port  Peer Address:Port Process
ESTAB 0      0          127.0.0.1:18000    127.0.0.1:38828       
ESTAB 0      0          127.0.0.1:38828    127.0.0.1:18000       
ss -u; echo rc=$?
Recv-Q Send-Q Local Address:Port Peer Address:PortProcess
rc=0

ss -u 空输出 + rc=0:默认视图只含「已连接」UDP,本机没有;要看 UDP 监听端口需加 -a 或 -l(见 3.4 中 udp UNCONN 行)。

3.3 -n:不解析服务名

ss 默认会把端口号翻译成服务名(查 /etc/services),-n 关闭端口名解析。对比同一监听端口在两种模式下的显示:

ss -tl
State  Recv-Q Send-Q Local Address:Port  Peer Address:PortProcess
LISTEN 0      128          0.0.0.0:ssh        0.0.0.0:*          
LISTEN 0      128          0.0.0.0:2222       0.0.0.0:*          
LISTEN 0      5            0.0.0.0:8001       0.0.0.0:*          
LISTEN 0      5            0.0.0.0:8000       0.0.0.0:*          
LISTEN 0      5            0.0.0.0:8443       0.0.0.0:*          
LISTEN 0      5          127.0.0.1:18000      0.0.0.0:*          
LISTEN 0      128             [::]:ssh           [::]:*          
LISTEN 0      128             [::]:2222          [::]:*          
ss -tln | head -4
State  Recv-Q Send-Q Local Address:Port  Peer Address:PortProcess
LISTEN 0      128          0.0.0.0:22         0.0.0.0:*          
LISTEN 0      128          0.0.0.0:2222       0.0.0.0:*          
LISTEN 0      5            0.0.0.0:8001       0.0.0.0:*          
LISTEN 0      5            0.0.0.0:8000       0.0.0.0:*          
  • 22 号端口默认显示 ssh、加 -n 后显示 22;8000 在 Ubuntu 22.04 的 /etc/services 中无登记条目(netstat 篇 3.5 已实测),所以两种模式都显示数字。
  • 注意 -n 只关端口名解析:ss 对 IP 地址默认本来就显示数字,除非用 -r 主动反解主机名——这正好与 netstat 相反(netstat 默认反解,-n 全关)。

3.4 -l:监听套接字 与 -tuln 组合

-l 只看 LISTEN;-tuln = TCP + UDP + 监听 + 数字,是服务器排查标配。先挂一个 UDP 套接字再对比:

python3 -c "import socket,time; s=socket.socket(socket.AF_INET,socket.SOCK_DGRAM); s.bind((\"127.0.0.1\",9998)); time.sleep(30)" >/dev/null 2>&1 &
ss -l
Netid State  Recv-Q Send-Q Local Address:Port    Peer Address:PortProcess
nl    UNCONN 0      0               rtnl:kernel              *           
nl    UNCONN 960    0               rtnl:1819                *           
nl    UNCONN 4352   0            tcpdiag:ss/7263             *           
nl    UNCONN 960    0            tcpdiag:kernel              *           
nl    UNCONN 0      0               xfrm:kernel              *           
nl    UNCONN 0      0              audit:kernel              *           
nl    UNCONN 0      0          fiblookup:kernel              *           
nl    UNCONN 0      0                nft:kernel              *           
nl    UNCONN 0      0               uevent:kernel              *           
nl    UNCONN 0      0               genl:kernel              *           
udp   UNCONN 0      0          127.0.0.1:9998         0.0.0.0:*          
tcp   LISTEN 0      128          0.0.0.0:ssh          0.0.0.0:*          
tcp   LISTEN 0      128          0.0.0.0:2222         0.0.0.0:*          
tcp   LISTEN 0      5            0.0.0.0:8001         0.0.0.0:*          
tcp   LISTEN 0      5            0.0.0.0:8000         0.0.0.0:*          
tcp   LISTEN 0      5            0.0.0.0:8443         0.0.0.0:*          
tcp   LISTEN 0      5          127.0.0.1:18000        0.0.0.0:*          
tcp   LISTEN 0      128             [::]:ssh             [::]:*          
tcp   LISTEN 0      128             [::]:2222            [::]:*          
ss -tuln
Netid State  Recv-Q Send-Q Local Address:Port  Peer Address:PortProcess
udp   UNCONN 0      0          127.0.0.1:9998       0.0.0.0:*          
tcp   LISTEN 0      128          0.0.0.0:22         0.0.0.0:*          
tcp   LISTEN 0      128          0.0.0.0:2222       0.0.0.0:*          
tcp   LISTEN 0      5            0.0.0.0:8001       0.0.0.0:*          
tcp   LISTEN 0      5            0.0.0.0:8000       0.0.0.0:*          
tcp   LISTEN 0      5            0.0.0.0:8443       0.0.0.0:*          
tcp   LISTEN 0      5          127.0.0.1:18000      0.0.0.0:*          
tcp   LISTEN 0      128             [::]:22            [::]:*          
tcp   LISTEN 0      128             [::]:2222          [::]:*          

要点:

  • 不加 -t/-u 限定时,ss -l 会带出一堆 nl(netlink)行——那是 ss 自己取数用的内核通道套接字,属正常现象;实战更常用 ss -tuln 直接限定 inet 族。
  • UDP 套接字状态显示 UNCONN(未连接);TCP 监听显示 LISTEN,Send-Q=128/5 就是各进程 listen() 的 backlog。
  • 与 netstat 篇 -tuln 实测输出逐行对齐:监听集合完全一致,仅表头措辞与状态缩写不同。

💡 说明:-tuln 是 ss 最高频的组合——先确认「这台服务器开了哪些端口」,Send-Q 列在 LISTEN 态就是各进程 listen() 的 backlog 上限(实测 128/5 与进程设定一致),排查「连接队列溢出」先看这一列;要落到进程再补 -p(见 3.5)。

3.5 -p:进程信息

-p 显示占用套接字的进程,格式为 users:(("进程名",pid=N,fd=M)):

ss -tlp
State  Recv-Q Send-Q Local Address:Port  Peer Address:PortProcess                           
LISTEN 0      128          0.0.0.0:ssh        0.0.0.0:*    users:(("sshd",pid=2423,fd=3))   
LISTEN 0      128          0.0.0.0:2222       0.0.0.0:*    users:(("sshd",pid=2914,fd=3))   
LISTEN 0      5            0.0.0.0:8001       0.0.0.0:*    users:(("python3",pid=4159,fd=3))
LISTEN 0      5            0.0.0.0:8000       0.0.0.0:*    users:(("python3",pid=7155,fd=3))
LISTEN 0      5            0.0.0.0:8443       0.0.0.0:*    users:(("python3",pid=4160,fd=3))
LISTEN 0      5          127.0.0.1:18000      0.0.0.0:*    users:(("python3",pid=7246,fd=3))
LISTEN 0      128             [::]:ssh           [::]:*    users:(("sshd",pid=2423,fd=4))   
LISTEN 0      128             [::]:2222          [::]:*    users:(("sshd",pid=2914,fd=4))   
ss -tnp | grep 18000
ESTAB 0      0          127.0.0.1:18000    127.0.0.1:38828 users:(("python3",pid=7246,fd=4))
ESTAB 0      0          127.0.0.1:38828    127.0.0.1:18000 users:(("python3",pid=7248,fd=3))
  • 与 netstat 的 PID/Program name 列相比,ss 多给了文件描述符号(fd=3 是监听 socket,fd=4 是 accept 出来的连接),定位代码里泄漏的 fd 时很有用。
  • TIME_WAIT 等无属主套接字在 -p 下 Process 列留空(内核中没有对应打开的 fd)。
  • 非 root 运行时只能归属自己的进程,与 netstat -p 相同。

3.6 -a:全部套接字

-a 显示全部(监听 + 已连接 + 各种中间状态),TCP 视图用 -at:

python3 -m http.server 18000 --bind 127.0.0.1 >/dev/null 2>&1 &
python3 /root/demo/ss/hold.py 18000 60 >/dev/null 2>&1 &
ss -at
State     Recv-Q Send-Q Local Address:Port  Peer Address:Port Process
LISTEN    0      128          0.0.0.0:ssh        0.0.0.0:*           
LISTEN    0      128          0.0.0.0:2222       0.0.0.0:*           
LISTEN    0      5            0.0.0.0:8001       0.0.0.0:*           
LISTEN    0      5            0.0.0.0:8000       0.0.0.0:*           
LISTEN    0      5            0.0.0.0:8443       0.0.0.0:*           
LISTEN    0      5          127.0.0.1:18000      0.0.0.0:*           
TIME-WAIT 0      0          127.0.0.1:8000     127.0.0.1:50772       
ESTAB     0      0          127.0.0.1:18000    127.0.0.1:38828       
TIME-WAIT 0      0          127.0.0.1:8000     127.0.0.1:50792       
TIME-WAIT 0      0          127.0.0.1:8000     127.0.0.1:46180       
TIME-WAIT 0      0          127.0.0.1:8000     127.0.0.1:50780       
TIME-WAIT 0      0          127.0.0.1:8000     127.0.0.1:46182       
TIME-WAIT 0      0          127.0.0.1:8000     127.0.0.1:51114       
TIME-WAIT 0      0          127.0.0.1:50068    127.0.0.1:8000        
TIME-WAIT 0      0          127.0.0.1:8000     127.0.0.1:50788       
TIME-WAIT 0      0          127.0.0.1:8000     127.0.0.1:50068       
TIME-WAIT 0      0          127.0.0.1:8000     127.0.0.1:50790       
TIME-WAIT 0      0          127.0.0.1:50798    127.0.0.1:8000        
TIME-WAIT 0      0          127.0.0.1:8000     127.0.0.1:50754       
TIME-WAIT 0      0          127.0.0.1:8000     127.0.0.1:51110       
TIME-WAIT 0      0          127.0.0.1:18080    127.0.0.1:46468       
TIME-WAIT 0      0          127.0.0.1:46182    127.0.0.1:8000        
TIME-WAIT 0      0          127.0.0.1:18080    127.0.0.1:46482       
TIME-WAIT 0      0          127.0.0.1:8000     127.0.0.1:50760       
TIME-WAIT 0      0          127.0.0.1:8000     127.0.0.1:46176       
ESTAB     0      0          127.0.0.1:38828    127.0.0.1:18000       
LISTEN    0      128             [::]:ssh           [::]:*           
LISTEN    0      128             [::]:2222          [::]:*           

输出节选(实测全表)。状态缩写对照 netstat:TIME-WAIT=TIME_WAIT、ESTAB=ESTABLISHED、CLOSE-WAIT=CLOSE_WAIT、UNCONN=无连接。大量 127.0.0.1:8000 的 TIME-WAIT 是本机其他服务的短连接残留,恰好演示了 TIME-WAIT 堆积的典型形态。

3.7 -s:统计摘要

-s 给出套接字总量摘要(先制造流量与状态再统计):

python3 -m http.server 18000 --bind 127.0.0.1 >/dev/null 2>&1 &
python3 -c "import socket,time; s=socket.socket(socket.AF_INET,socket.SOCK_DGRAM); s.bind((\"127.0.0.1\",9998)); time.sleep(20)" >/dev/null 2>&1 &
python3 /root/demo/ss/hold.py 18000 20 >/dev/null 2>&1 &
curl -s http://127.0.0.1:18000/ >/dev/null
ss -s
Total: 17
TCP:   70 (estab 4, closed 58, orphaned 0, timewait 24)

Transport Total     IP        IPv6
RAW       0         0         0        
UDP       1         1         0        
TCP       12        10        2        
INET      12        10        2        
FRAG      0         0         0        

解读:

  • 首行 Total: 17 是当前活跃套接字总数;第二行 TCP: 70 (estab 4, closed 58, ...) 是 TCP 家族总量,括号内按状态细分:4 条已建立、58 条已关闭(内核对象尚未释放)、24 条 TIME-WAIT。
  • Transport 表按协议族给出 IPv4/IPv6 分布:UDP 1 个(9998)、TCP 12 个(IPv4 10 + IPv6 2)。
  • ss -s 是轻量摘要,适合塞进监控脚本;要看逐计数器的协议统计(packets/errs/drop),仍用 netstat -s 或 nstat。

3.8 -m:套接字内存(skmem)

-m 在每条连接下追加 skmem 行,展示内核为该套接字分配的内存:

python3 /root/demo/ss/echo_server.py 7778 60 >/dev/null 2>&1 &
python3 /root/demo/ss/echo_client.py 7778 58 >/dev/null 2>&1 &
ss -tm
State Recv-Q Send-Q Local Address:Port  Peer Address:Port Process
ESTAB 0      0          127.0.0.1:7778     127.0.0.1:60738
	 skmem:(r0,rb131072,t0,tb2626560,f0,w0,o0,bl0,d0)
ESTAB 0      0          127.0.0.1:60738    127.0.0.1:7778
	 skmem:(r0,rb131072,t0,tb2626560,f0,w0,o0,bl0,d0)

skmem 字段解读:

字段含义
r / rb接收队列已用字节 / 接收缓冲区上限
t / tb发送队列已用字节 / 发送缓冲区上限
fforward allocation(预分配给接收的内存)
wwmem allocation(发送侧已记账内存)
o选项等辅助内存
bl协议私有 backlog(如 UDP 积压)
dsock 之外挂的内存(如 UNIX 套接字的 skb)

实测两条连接的 rb=131072(128KB 接收缓冲)、tb=2626560(约 2.5MB 发送缓冲上限,空闲时 t=0 未占用)。排障时若 r/rb 或 t/tb 长期逼近,说明缓冲区打满、应用读取或网络发送跟不上。

3.9 -o:计时器

-o 追加 timer 列,显示套接字上的内核定时器:

ss -to
State Recv-Q Send-Q Local Address:Port  Peer Address:Port Process
ESTAB 0      0          127.0.0.1:7778     127.0.0.1:60738
ESTAB 0      0          127.0.0.1:60738    127.0.0.1:7778  timer:(keepalive,119min,0)
  • 同一对连接,客户端(60738,echo_client.py 开启了 SO_KEEPALIVE)显示 timer:(keepalive,119min,0):keepalive 定时器、距下次探测约 119 分钟、已重传 0 次;服务端未开 keepalive,timer 列为空——正好构成对照。
  • timer 取值类型:on(等待 ACK/数据的重传定时器)、keepalive、timewait(TIME_WAIT 回收定时器)、off。排障口诀:大量连接 timer:on 且重传次数增长 = 对端无响应或网络异常;TIME_WAIT 连接会显示 timewait 定时器倒计时。

3.10 -i:TCP 内部信息(cwnd / rtt)

-i 展示每条 TCP 连接的内部参数,是观测拥塞窗口与往返时延的主要手段:

ss -ti
State Recv-Q Send-Q Local Address:Port  Peer Address:Port Process
ESTAB 0      0          127.0.0.1:7778     127.0.0.1:60738
	 cubic wscale:7,7 rto:201 rtt:0.008/0.003 ato:40 mss:32768 pmtu:65535 rcvmss:536 advmss:65483 cwnd:10 bytes_sent:17 bytes_acked:17 bytes_received:13 segs_out:2 segs_in:4 data_segs_out:1 data_segs_in:1 send 328Gbps lastsnd:2021 lastrcv:2021 lastack:2021 pacing_rate 591Gbps delivery_rate 32.8Gbps delivered:2 app_limited rcv_space:65483 rcv_ssthresh:65483 minrtt:0.008
ESTAB 0      0          127.0.0.1:60738    127.0.0.1:7778
	 cubic wscale:7,7 rto:201 rtt:0.009/0.005 ato:40 mss:32768 pmtu:65535 rcvmss:536 advmss:65483 cwnd:10 bytes_sent:13 bytes_acked:14 bytes_received:17 segs_out:4 segs_in:3 data_segs_out:1 data_segs_in:1 send 291Gbps lastsnd:2025 lastrcv:2025 lastack:2025 pacing_rate 575Gbps delivery_rate 87.4Gbps delivered:2 app_limited rcv_space:65495 rcv_ssthresh:65495 minrtt:0.003

关键字段解读:

字段实测值含义
rtt:0.008/0.003毫秒平滑 RTT / RTT 方差(回环连接极小);跨网连接通常 0.5~200ms
rto:201毫秒重传超时 = RTT + 4×方差 的推算值
cwnd:10段拥塞窗口(初始 10),持续增长说明链路健康
mss:32768 / pmtu:65535字节最大段长 / 路径 MTU(回环为 65535)
bytes_sent/acked/received字节累计收发统计
lastsnd / lastrcv / lastack毫秒距上次发送/接收/ACK 的时长,判断连接是否僵死
pacing_rate / delivery_ratebps发送速率估计
app_limited标记应用层供数不足(非网络瓶颈)——本例 echo 对空闲,正好命中

排障经验:ss -ti 中 rtt 突增、cwnd 回落到个位数、retrans 计数增长三者同时出现,基本可判定链路质量恶化。

3.11 -e:详细信息(ino / uid)

-e 追加套接字元信息:inode 号(ino)、内核 sk 指针(sk)、cgroup 归属等。root 属主的套接字不显示 uid(uid 0 省略),用 nobody(65534)建立连接即可看到 uid 字段:

python3 -m http.server 18000 --bind 127.0.0.1 >/dev/null 2>&1 &
cp /root/demo/ss/hold.py /tmp/hold-uid.py && chmod 644 /tmp/hold-uid.py
setpriv --reuid=65534 --regid=65534 --clear-groups python3 /tmp/hold-uid.py 18000 40 >/dev/null 2>&1 &
ss -tne | grep 18000
ESTAB 0      0          127.0.0.1:47858    127.0.0.1:18000 uid:65534 ino:552386 sk:a001 cgroup:/ <->
ESTAB 0      0          127.0.0.1:18000    127.0.0.1:47858 ino:554725 sk:a004 cgroup:/ <->
  • uid:65534 是 nobody 属主的连接,本端 root 服务的行不显示 uid——可用来快速区分「哪些连接是普通用户进程发起的」。
  • ino 是套接字 inode,与 lsof//proc/<pid>/fd 里的 socket:[ino] 对应,是把连接关联到进程的中间凭据;sk 是内核 sock 结构地址。
  • 行尾 <-> 表示该套接字双向统计可用。

3.12 -4 / -6:地址族过滤

-4/-6 分别只显示 IPv4/IPv6 套接字。准备三个监听:IPv4 通配(8080)、仅回环 IPv4(18081)、仅 IPv6 回环([::1]:9996):

python3 -m http.server 8080 >/dev/null 2>&1 &
python3 -m http.server 18081 --bind 127.0.0.1 >/dev/null 2>&1 &
python3 -c "import socket,time; s=socket.socket(socket.AF_INET6); s.bind((\"::1\",9996)); s.listen(1); time.sleep(30)" >/dev/null 2>&1 &
ss -4 -tln
State  Recv-Q Send-Q Local Address:Port  Peer Address:PortProcess
LISTEN 0      128          0.0.0.0:22         0.0.0.0:*          
LISTEN 0      128          0.0.0.0:2222       0.0.0.0:*          
LISTEN 0      5            0.0.0.0:8001       0.0.0.0:*          
LISTEN 0      5            0.0.0.0:8000       0.0.0.0:*          
LISTEN 0      5            0.0.0.0:8080       0.0.0.0:*          
LISTEN 0      5            0.0.0.0:8443       0.0.0.0:*          
LISTEN 0      5          127.0.0.1:18081      0.0.0.0:*          
ss -6 -tln
State  Recv-Q Send-Q Local Address:Port Peer Address:PortProcess
LISTEN 0      128             [::]:22           [::]:*          
LISTEN 0      128             [::]:2222         [::]:*          
LISTEN 0      1              [::1]:9996         [::]:*          
  • -4 表里全是 0.0.0.0/127.0.0.1 的 IPv4 监听;-6 表里是 [::]/[::1] 的 IPv6 监听,互不混杂。
  • sshd 在两张表各有一行(0.0.0.0:22 与 [::]:22),是双栈服务的典型形态;排查「IPv6 有没有监听」时直接 ss -6 -tln。

3.13 -d:DCCP 套接字

-d 只显示 DCCP(数据报拥塞控制协议)套接字。DCCP 极少部署,本机为空但命令正常:

ss -d; echo rc=$?
State Recv-Q Send-Q Local Address:Port Peer Address:PortProcess
rc=0

顺带从 --help 可知 ss 还支持 -w(RAW)、-S(SCTP)、-M(MPTCP)、-0(packet)、--tipc、--vsock 等族过滤,用法与 -d 一致。

3.14 -x:UNIX 域套接字

-x 显示 UNIX 域套接字,Netid 为 u_str(流式)。默认(不加 -a)只显示已连接的:

rm -f /tmp/demo.sock
python3 /root/demo/ss/unix_server.py /tmp/demo.sock 40 >/dev/null 2>&1 &
python3 /root/demo/ss/unix_client.py /tmp/demo.sock 40 >/dev/null 2>&1 &
ss -x
Netid State Recv-Q Send-Q                Local Address:Port   Peer Address:Port  Process
u_str ESTAB 0      0                                 * 556401            * 556400
u_str ESTAB 0      0                                 * 550427            * 0
u_str ESTAB 0      0                                 * 556400            * 556401
u_str ESTAB 0      0      /tmp/cm-scp.EUIcxcQwQrZqoqaW 551825            * 549842
u_str ESTAB 0      0                                 * 549842            * 551825

已连接行的 Local/Peer 显示的是套接字 inode 号(只有监听行显示路径),要看到进程归属与路径,加 -ap:

ss -xap | grep -E "t.sock|State"
Netid State  Recv-Q Send-Q Local Address:Port   Peer Address:Port  Process
u_str ESTAB  0      0        /tmp/t.sock 557634            * 552588 users:(("python3",pid=8442,fd=4))
u_str LISTEN 0      1        /tmp/t.sock 557633            * 0      users:(("python3",pid=8442,fd=3))
ss -xlp | grep -E "t.sock|State"
Netid State  Recv-Q Send-Q Local Address:Port   Peer Address:Port  Process
u_str LISTEN 0      1        /tmp/t.sock 557633            * 0      users:(("python3",pid=8442,fd=3))
  • -xap 一次给出路径、状态与 users:(("python3",pid=8442,fd=4))——UNIX 域排障(谁占着 /tmp/*.sock、fd 泄漏到哪)三板斧:ss -x 看总量、ss -xa 看监听、ss -xap 归属进程。
  • u_str ESTAB ... * 550427 * 0 这种对端为 * 0 的行是尚未被 accept 或对端已关闭的匿名连接。

3.15 状态过滤:state established / time-wait

ss 支持把状态作为过滤表达式直接下推内核(--help 中 STATE-FILTER 语法的实测)。先制造 TIME_WAIT(curl 短连接刚结束)与 ESTABLISHED(hold.py 挂住):

python3 -m http.server 18000 --bind 127.0.0.1 >/dev/null 2>&1 &
python3 /root/demo/ss/hold.py 18000 25 >/dev/null 2>&1 &
curl -s http://127.0.0.1:18000/ >/dev/null
ss state time-wait
Netid Recv-Q Send-Q Local Address:Port  Peer Address:Port Process
tcp   0      0          127.0.0.1:8000     127.0.0.1:59154
tcp   0      0          127.0.0.1:8000     127.0.0.1:59184
tcp   0      0          127.0.0.1:7778     127.0.0.1:60738
tcp   0      0          127.0.0.1:8000     127.0.0.1:33612
tcp   0      0          127.0.0.1:8000     127.0.0.1:59084
tcp   0      0          127.0.0.1:18000    127.0.0.1:46056

输出节选(实测共 26 行,其余均为 127.0.0.1:8000 相关残留)。其中 127.0.0.1:18000 ↔ 127.0.0.1:46056 就是本次 curl 主动关闭后留下的 TIME_WAIT。

ss state established
Netid Recv-Q Send-Q Local Address:Port   Peer Address:Port  Process
tcp   0      0          127.0.0.1:18000    127.0.0.1:46072
tcp   0      0          127.0.0.1:46072    127.0.0.1:18000
ss state listening | head -10
Netid Recv-Q Send-Q Local Address:Port  Peer Address:PortProcess
tcp   0      128          0.0.0.0:ssh        0.0.0.0:*          
tcp   0      128          0.0.0.0:2222       0.0.0.0:*          
tcp   0      5            0.0.0.0:8001       0.0.0.0:*          
tcp   0      5            0.0.0.0:8000       0.0.0.0:*          
tcp   0      5            0.0.0.0:8443       0.0.0.0:*          
tcp   0      5          127.0.0.1:18000      0.0.0.0:*          
tcp   0      128             [::]:ssh           [::]:*          
tcp   0      128             [::]:2222          [::]:*          
  • 状态名用小写连字符:established、time-wait、close-wait、listening、syn-sent、fin-wait-1 等(对照 netstat 需要靠 grep TIME_WAIT 实现)。
  • 不加 -t 时 state 过滤会带出其他族里「同名状态」的套接字(如 UNIX 流的 ESTAB),实战建议写成 ss -tn state established 明确限定 TCP。
  • STATE-FILTER 还提供聚合名:connected(所有已连接类)、synchronized、bucket(syn-recv+time-wait)、big、all,例如 ss state bucket 一条命令集中查看半开与 TIME_WAIT 队列。

3.16 地址过滤:dst / src / dport

ss 的表达式过滤同样在内核侧执行,dst 匹配对端、src 匹配本端、dport/sport 匹配对端/本端端口:

python3 -m http.server 18000 --bind 127.0.0.1 >/dev/null 2>&1 &
python3 /root/demo/ss/hold.py 18000 20 >/dev/null 2>&1 &
ss -tn dst 127.0.0.1
State Recv-Q Send-Q Local Address:Port  Peer Address:Port Process
ESTAB 0      0          127.0.0.1:37216    127.0.0.1:22          
ESTAB 0      0          127.0.0.1:22       127.0.0.1:37216       
ESTAB 0      0          127.0.0.1:18000    127.0.0.1:54206       
ESTAB 0      0          127.0.0.1:54206    127.0.0.1:18000       
ss -tn src 127.0.0.1
State Recv-Q Send-Q Local Address:Port  Peer Address:Port Process
ESTAB 0      0          127.0.0.1:37216    127.0.0.1:22          
ESTAB 0      0          127.0.0.1:22       127.0.0.1:37216       
ESTAB 0      0          127.0.0.1:18000    127.0.0.1:54206       
ESTAB 0      0          127.0.0.1:54206    127.0.0.1:18000       
ss -tn dport = :18000
State Recv-Q Send-Q Local Address:Port  Peer Address:Port Process
ESTAB 0      0          127.0.0.1:54206    127.0.0.1:18000       
  • 全部连接都在回环上,所以 dst 与 src 命中同样 4 行;真实场景中它们分别用于「看谁连着我」(dst <客户端IP>)和「看我连着谁」(src <本机IP>)。
  • dport = :18000 精确匹配对端端口为 18000 的连接;多个表达式并列即 AND(如 ss -tn dst 127.0.0.1 dport = :18000,见 4.3 实测),也支持 !=、>、< 比较与 or。

3.17 -K:强制关闭连接(谨慎使用)

-K(--kill)对命中过滤条件的套接字执行 SOCK_DESTROY,立即发 RST 断开。语法实测如下——先建一条挂起连接,再用端口过滤器定向关闭:

python3 /root/demo/ss/echo_server.py 7779 90 >/dev/null 2>&1 &
python3 /root/demo/ss/hold.py 7779 90 >/dev/null 2>&1 &
ss -tn | grep 7779
ESTAB 0      0          127.0.0.1:57956    127.0.0.1:7779        
ESTAB 0      0          127.0.0.1:7779     127.0.0.1:57956       
ss -K dport = :7779
SOCK_DESTROY answers: Operation not permitted
Netid State Recv-Q Send-Q Local Address:Port Peer Address:PortProcess
ss -tn | grep 7779; echo rc=$?
ESTAB 0      0          127.0.0.1:57956    127.0.0.1:7779        
ESTAB 0      0          127.0.0.1:7779     127.0.0.1:57956       
rc=0
grep CapEff /proc/self/status
CapEff: 00000000a80425fb

实测结论(谨慎项):

  • 命令与过滤器语法正确(ss -K dport = :7779),但本实测环境返回 SOCK_DESTROY answers: Operation not permitted,连接未被关闭——SOCK_DESTROY 需要内核授予 CAP_NET_ADMIN 能力,本环境 CapEff 位图中未包含该位(0xa80425fb 第 12 位为 0),即便以 root 运行也会被拒绝。
  • 在标准服务器上 root 通常具备完整能力,等效命令将直接列出被关闭的套接字并断开连接。正因为它是唯一能在不杀进程的情况下定向拆掉一条 TCP 连接的内置工具,务必始终带过滤条件(如 dport = :端口),裸敲 ss -K 会断开当前系统全部命中套接字。
  • 能力受限环境的替代:kill <pid>(杀进程)、conntrack -D(删跟踪表项)或重启应用。

3.18 技术拓展:ss 与 netstat 的取数通道与映射

ss 隶属 iproute2 工具族,通过 netlink(NETLINK_SOCK_DIAG) 一次内核调用批量取回套接字信息,过滤器在内核侧生效;netstat 隶属 net-tools,逐个读取 /proc/net/tcp 等文本伪文件再在用户态解析过滤。连接数上万时,netstat 的 CPU 与延迟随连接数线性增长,ss 增长平缓,这是「ss 取数更快」的根源,也是 Ubuntu 22.04 默认不预装 net-tools、而 netstat 官方已停止功能维护的原因。两套命令常用组合映射(反向对照 netstat 篇第六节):

用途ss 写法netstat 等价写法
监听端口总览ss -tulnnetstat -tuln
监听 + 进程ss -tlnpnetstat -tlnp
全部 TCP(数字)ss -tannetstat -ant
按状态筛选ss -tn state time-waitnetstat -ant | grep TIME_WAIT
按地址/端口筛选ss -tn dst IP dport = :Nnetstat -ant | grep IP
统计摘要ss -snetstat -s(逐计数器,配合 nstat)
套接字内存ss -tm无对应(netstat 不支持)
TCP 内部参数ss -ti无对应(可间接看 ip tcp_metrics)
计时器ss -tonetstat -o(显示有限)
强制关连ss -K无对应

ss 独有且高频的三个能力值得写进运维手册:state 表达式(内核侧过滤)、-i(cwnd/rtt 直读)、-K(定向断连,需 CAP_NET_ADMIN,见 3.17 实测受限现象)。

💡 说明:迁移建议很简单——新脚本一律用 ss;只有拿到一台只有 net-tools 的老机器才回退 netstat,两者写法按上表逐行对应即可,参数语义完全等价。

四、实战示例

4.1 端口监听与进程归属一条龙

python3 -m http.server 18000 --bind 127.0.0.1 >/dev/null 2>&1 &
python3 /root/demo/ss/hold.py 18000 25 >/dev/null 2>&1 &
ss -tlp | grep 18000
LISTEN 0      5          127.0.0.1:18000      0.0.0.0:*    users:(("python3",pid=8456,fd=3))
ss -tnp | grep 18000
ESTAB 0      0          127.0.0.1:50298    127.0.0.1:18000 users:(("python3",pid=8458,fd=3))
ESTAB 0      0          127.0.0.1:18000    127.0.0.1:50298 users:(("python3",pid=8456,fd=4))

一条 -tlp 确认监听与进程;一条 -tnp 看现存连接两端的进程对(8456 服务端 fd=4 / 8458 客户端 fd=3)。

4.2 连接状态分布统计

ss -tan | grep 18000 | tr -s " " | cut -d" " -f1 | sort | uniq -c
      2 ESTAB
      1 LISTEN
      1 TIME-WAIT

压测时 ESTAB 数应约等于并发数,TIME-WAIT 堆积量反映短连接频率,一条管道即可出报表。

4.3 组合过滤:定位到具体连接

ss -tn dst 127.0.0.1 dport = :18000
State Recv-Q Send-Q Local Address:Port  Peer Address:Port Process
ESTAB 0      0          127.0.0.1:50298    127.0.0.1:18000       

dst 与 dport 并列即 AND,从连接表里一步筛出「对端是 127.0.0.1 且目标端口 18000」的客户端连接;换成 sport = :18000 则看服务端视角。

4.4 观察连接健康度(rtt / cwnd)

ss -ti dst 127.0.0.1
State Recv-Q Send-Q Local Address:Port  Peer Address:Port Process
ESTAB 0      0          127.0.0.1:50298    127.0.0.1:18000
	 cubic wscale:7,7 rto:205 rtt:0.014/0.007 mss:32741 pmtu:65535 rcvmss:536 advmss:65483 cwnd:10 bytes_acked:1 segs_out:2 segs_in:1 send 187Gbps lastsnd:1064 lastrcv:1064 lastack:1064 pacing_rate 374Gbps delivered:1 app_limited rcv_space:65495 rcv_ssthresh:65495 minrtt:0.014
ESTAB 0      0          127.0.0.1:18000    127.0.0.1:50298
	 cubic wscale:7,7 rto:205 rtt:0.01/0.005 mss:32768 pmtu:65535 rcvmss:536 advmss:65483 cwnd:10 segs_in:2 send 262Gbps lastsnd:1064 lastrcv:1064 lastack:1064 pacing_rate 524Gbps delivered:1 app_limited rcv_space:65483 rcv_ssthresh:65483 minrtt:0.01

过滤与信息参数可叠加:-ti + dst 一步拿到目标连接的 rtt/cwnd/收发字节。巡检脚本建议固定采集 ss -ti state established 的 rtt 与 lastsnd 两个字段做趋势。

五、注意事项与常见问题

Q1:ss -K 报 SOCK_DESTROY answers: Operation not permitted? SOCK_DESTROY 需要 CAP_NET_ADMIN 能力。实测环境 root 的 CapEff 为 0xa80425fb,不含该能力位(见 3.17 实测),因此即便 root 也被内核拒绝;安全加固基线收窄了能力位的运行环境(及 gVisor 等沙箱场景)都会出现同样报错,先 grep CapEff /proc/self/status 确认能力位再判断。

Q2:ss 显示的服务名和端口号为什么对不上我 grep 的? ss 默认按 /etc/services 翻译端口名(22→ssh),-n 才显示数字;Ubuntu 22.04 中 8000 无登记名恒显数字(netstat 篇 3.5 实测)。写脚本判断端口一律用 ss -tln | grep -w 18000 这种数字匹配,避免两种模式混用。

Q3:ss 默认输出为什么和 netstat 不一样? 三点差异:ss 默认不含 UNIX 域套接字、不做主机名反解(更快)、状态用缩写(ESTAB/TIME-WAIT)。要 netstat 风格的全量视图用 ss -a。

Q4:ss -l 怎么多出一堆 nl/xfrm 行? 那是 netlink、xfrm 等内核通道套接字,ss 取数本身也要用到它们。加 -t/-u 限定协议族即可屏蔽,标准写法是 ss -tuln。

Q5:Recv-Q/Send-Q 和 netstat 含义一致吗? 一致。ESTAB 态是字节队列;LISTEN 态 Recv-Q=待 accept 连接数、Send-Q=listen backlog(实测 3.4 表中 sshd 为 128、http.server 为 5)。LISTEN 行 Recv-Q 长期顶满 Send-Q 就要扩 backlog 或排查应用 accept 速度。

Q6:ss -s 的 Total 和 TCP 行为什么差很多? Total 是当前活跃套接字,TCP: 70 (estab 4, closed 58, ...) 包含已 close 但内核对象未释放的套接字与 TIME-WAIT(见 3.7 实测:Total 17 与 TCP 70 并存属正常),看并发数以括号里的 estab 为准。

Q7:state 过滤把 UNIX 套接字也带出来了? ss state established 不加 -t 时会匹配所有族的同名状态(实测 3.15 注)。统一加 -t(或 -u)限定协议族再过滤。

六、参考链接