netstat 命令详解与参数实测(Ubuntu 22.04)
netstat 逐参数实测详解:默认输出、-t/-u 协议过滤、-l 监听、-n 数字与 http-alt 服务名对照、-tuln 逐列解读、-p 进程定位、-a、-s 协议统计、-r 路由、-i 接口、-c 连续刷新,实测 LISTEN/ESTABLISHED/TIME_WAIT/CLOSE_WAIT 状态全集与 Recv-Q/Send-Q 非零队列判读,附 netstat 与 ss 命令映射表,全部回显在 Ubuntu 22.04(net-tools 2.10)实测通过。
netstat 命令详解与参数实测(Ubuntu 22.04)
目标:全面掌握 netstat 的每一个常用参数——默认输出、
-t/-u协议过滤、-l监听、-n数字显示、-tuln服务器排查标配、-p进程定位、-a全部套接字、-s协议统计、-r路由表、-i接口统计、-c连续刷新,并实测 LISTEN/ESTABLISHED/TIME_WAIT/CLOSE_WAIT 四种 TCP 状态与 Recv-Q/Send-Q 非零队列的判读方法,附 netstat 与 ss 的命令映射表,全部命令与回显已在 Ubuntu 22.04(net-tools 2.10)实测通过。
一、环境信息
- 操作系统:Ubuntu 22.04.5 LTS(x86_64)
- netstat 版本:net-tools 2.10-alpha(
netstat --version实测首行,属于 net-tools 2.10 系列) - netstat 由
net-tools软件包提供,Ubuntu 22.04 执行apt install net-tools即可安装 /etc/services(端口名 ↔ 服务名映射数据库)由netbase 6.3包提供;本机实测环境初始缺失该文件,已通过apt-get install netbase补齐(标准 Ubuntu 22.04 服务器默认预装,一般无需手动操作)- 测试数据目录:
/root/demo/netstat/(存放模拟连接用的 Python 辅助脚本) - 演示端口:18000(演示用 HTTP 服务)、8080(服务名对照)、7777(监听队列)、8888(收发队列)、9998(UDP)
二、命令概览
2.1 语法与测试数据
netstat(network statistics)用于显示内核中的网络连接、路由表、接口统计与协议统计等信息,基本语法是:
netstat [地址族] [选项]
netstat 的连接数据来自内核伪文件(/proc/net/tcp、/proc/net/udp、/proc/net/unix 等),路由与接口信息通过 ioctl//proc/net/route、/proc/net/dev 读取。默认(不带 -a)只显示已连接的套接字,不含监听服务端;-a 才会把 LISTEN 等状态一并列出。
为让每条参数都有真实数据可看,先在 /root/demo/netstat/ 准备 5 个小的 Python 辅助脚本(内容如下,均可直接复制使用),并约定:每个演示块自带数据准备与清理,互不依赖。
# /root/demo/netstat/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/netstat/close_wait.py —— 完成一次 HTTP 交互后不调用 close,制造 CLOSE_WAIT
import socket, sys, time
port = int(sys.argv[1]); secs = int(sys.argv[2])
s = socket.create_connection(("127.0.0.1", port))
s.sendall(b"GET / HTTP/1.0\r\n\r\n")
time.sleep(1)
s.recv(65536)
time.sleep(secs)
# /root/demo/netstat/listen_noaccept.py —— 只监听不 accept,制造 accept 队列积压
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(2)
time.sleep(secs)
# /root/demo/netstat/noread_server.py —— accept 后不读取数据,制造接收队列积压
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()
time.sleep(secs)
# /root/demo/netstat/send_noread.py —— 向对端发送 200KB 数据且对端不读,制造发送队列积压
import socket, sys, time
port = int(sys.argv[1]); secs = int(sys.argv[2])
s = socket.create_connection(("127.0.0.1", port))
s.sendall(b"x" * 200000)
time.sleep(secs)
演示服务用 Python 自带的 http.server 起一个监听(LISTEN 态),用 hold.py 挂一条保持连接(ESTABLISHED 态),用 curl 发短请求(结束后立刻抓取可得 TIME_WAIT 态)。
2.2 --help 全量输出
netstat --help 输出全部参数清单(实测原样保留,可作为参数速查。注意实测回显中地址族清单出现在开头、末尾只留标题行,这是 net-tools 把 stdout/stderr 分开缓冲导致的排列现象):
inet (DARPA Internet) inet6 (IPv6) ax25 (AMPR AX.25)
netrom (AMPR NET/ROM) ipx (Novell IPX) ddp (Appletalk DDP)
x25 (CCITT X.25)
usage: netstat [-vWeenNcCF] [<Af>] -r netstat {-V|--version|-h|--help}
netstat [-vWnNcaeol] [<Socket> ...]
netstat { [-vWeenNac] -i | [-cnNe] -M | -s [-6tuw] }
-r, --route display routing table
-i, --interfaces display interface table
-g, --groups display multicast group memberships
-s, --statistics display networking statistics (like SNMP)
-M, --masquerade display masqueraded connections
-v, --verbose be verbose
-W, --wide don't truncate IP addresses
-n, --numeric don't resolve names
--numeric-hosts don't resolve host names
--numeric-ports don't resolve port names
--numeric-users don't resolve user names
-N, --symbolic resolve hardware names
-e, --extend display other/more information
-p, --programs display PID/Program name for sockets
-o, --timers display timers
-c, --continuous continuous listing
-l, --listening display listening server sockets
-a, --all display all sockets (default: connected)
-F, --fib display Forwarding Information Base (default)
-C, --cache display routing cache instead of FIB
-Z, --context display SELinux security context for sockets
<Socket>={-t|--tcp} {-u|--udp} {-U|--udplite} {-S|--sctp} {-w|--raw}
{-x|--unix} --ax25 --ipx --netrom
<AF>=Use '-6|-4' or '-A <af>' or '--<af>'; default: inet
List of possible address families (which support routing):
从 usage 行可以直接读出 netstat 的参数分组逻辑:-r 路由表、-i 接口表、-s 统计各自成组,套接字组则由 <Socket>(-t/-u/-x 等)与显示控制项(-n/-a/-l/-p)自由组合。
2.3 版本信息
netstat --version; echo rc=$?
net-tools 2.10-alpha
Fred Baumgarten, Alan Cox, Bernd Eckenfels, Phil Blundell, Tuan Hoang, Brian Micek and others
+NEW_ADDRT +RTF_IRTT +RTF_REJECT +FW_MASQUERADE +I18N +SELINUX
AF: (inet) +UNIX +INET +INET6 +IPX +AX25 +NETROM +X25 +ATALK +ECONET +ROSE -BLUETOOTH
HW: +ETHER +ARC +SLIP +PPP +TUNNEL -TR +AX25 +NETROM +X25 +FR +ROSE +ASH +SIT +FDDI +HIPPI +HDLC/LAPB +EUI64
rc=0
首行 net-tools 2.10-alpha 即版本号。net-tools 最后一次正式维护已止于 2.10 系列,官方推荐的新工具是 iproute2 的 ss(对照见 3.16 节映射表)。
三、参数逐项实测
3.1 默认输出(无参数)
不带任何参数时,netstat 只列出已连接的 inet 套接字与已连接的 UNIX 域套接字(标题写着 w/o servers,即不含服务端),随后是 UNIX 域套接字长清单。先起一个演示服务并挂一条保持连接:
python3 -m http.server 18000 --bind 127.0.0.1 >/dev/null 2>&1 &
python3 /root/demo/netstat/hold.py 18000 25 >/dev/null 2>&1 &
netstat | head -14
Active Internet connections (w/o servers)
Proto Recv-Q Send-Q Local Address Foreign Address State
tcp 0 0 localhost:40512 localhost:18000 ESTABLISHED
tcp 0 0 localhost:18000 localhost:40512 ESTABLISHED
tcp 0 0 localhost:8000 localhost:48644 TIME_WAIT
Active UNIX domain sockets (w/o servers)
Proto RefCnt Flags Type State I-Node Path
要点:
- 标题
Active Internet connections (w/o servers)表明默认视图不含 LISTEN 服务端——这就是很多新手「明明服务在跑,netstat 却看不到」的原因,需要-a或-l(见 3.4)。 - 回环连接会出现两行(本端
localhost:40512 → localhost:18000与对端localhost:18000 → localhost:40512),因为客户端、服务端两个套接字都属于本机。 - 默认视图里也能看到 TIME_WAIT 等已断开连接的残留状态;UNIX 域套接字部分默认极长,本文用
head -14截取首部。
💡 技术拓展:netstat 显示的「连接」本质是内核套接字的状态快照,同类信息在 Linux 上共有三代工具——第一代 netstat(读 /proc 伪文件,已停止维护)、第二代 lsof(
lsof -i,按进程视角看套接字)、第三代 iproute2 的 ss(走 netlink 接口,速度快、过滤强)。本文实测以 netstat 为主,第六节给出与 ss 的完整命令映射。
3.2 -t:只看 TCP 连接
-t(--tcp)把视图限定到 inet TCP 套接字,UNIX 域部分不再出现,输出干净许多:
netstat -t
Active Internet connections (w/o servers)
Proto Recv-Q Send-Q Local Address Foreign Address State
tcp 0 0 localhost:40512 localhost:18000 ESTABLISHED
tcp 0 0 localhost:18000 localhost:40512 ESTABLISHED
tcp 0 0 localhost:8000 localhost:48644 TIME_WAIT
-t 与默认输出的差异只在「过滤范围」:默认连 UDP、UNIX 一起显示(只要不是服务端),-t 只留 TCP。配合 -n、-l、-p 等,是 netstat -tuln、netstat -tlnp 这类组合的基础。
3.3 -u:只看 UDP 套接字
-u(--udp)限定 UDP。注意 UDP 是无连接协议,「已连接」视图通常为空:
netstat -u; echo rc=$?
Active Internet connections (w/o servers)
Proto Recv-Q Send-Q Local Address Foreign Address State
rc=0
输出只剩表头、退出码仍为 0——这不是出错,而是默认视图下没有「已连接」的 UDP 套接字。要看本机 UDP 端口(DNS 缓存、NTP 等),必须加 -a 或 -l 显示未连接但已绑定的套接字(见 3.6 中 -tuln 的 udp 行)。
3.4 -l:只看监听套接字
-l(--listening)只显示 LISTEN 状态的服务端套接字,是「这台服务器开了哪些端口」的标准问法:
netstat -l | head -14
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State
tcp 0 0 0.0.0.0:ssh 0.0.0.0:* LISTEN
tcp 0 0 0.0.0.0:2222 0.0.0.0:* LISTEN
tcp 0 0 0.0.0.0:8001 0.0.0.0:* LISTEN
tcp 0 0 0.0.0.0:8000 0.0.0.0:* LISTEN
tcp 0 0 0.0.0.0:8443 0.0.0.0:* LISTEN
tcp 0 0 localhost:18000 0.0.0.0:* LISTEN
tcp6 0 0 [::]:ssh [::]:* LISTEN
tcp6 0 0 [::]:2222 [::]:* LISTEN
Active UNIX domain sockets (only servers)
Proto RefCnt Flags Type State I-Node Path
0.0.0.0:ssh表示监听本机所有 IPv4 地址;[::]:ssh是对应的 IPv6 通配监听(双栈服务会在两张表各占一行)。localhost:18000表示只监听回环地址,外部无法访问。- Foreign Address 列对 LISTEN 行固定显示
*(无对端概念)。
只想看 TCP 监听、去掉 UNIX 部分,用 netstat -lt:
netstat -lt
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State
tcp 0 0 0.0.0.0:ssh 0.0.0.0:* LISTEN
tcp 0 0 0.0.0.0:2222 0.0.0.0:* LISTEN
tcp 0 0 0.0.0.0:8001 0.0.0.0:* LISTEN
tcp 0 0 0.0.0.0:8000 0.0.0.0:* LISTEN
tcp 0 0 0.0.0.0:8443 0.0.0.0:* LISTEN
tcp 0 0 localhost:18000 0.0.0.0:* LISTEN
tcp6 0 0 [::]:ssh [::]:* LISTEN
tcp6 0 0 [::]:2222 [::]:* LISTEN
3.5 -n:不解析名称(服务名 vs 端口号对照)
-n(--numeric)跳过三类解析:主机名反解(IP → localhost 等)、端口名(端口号 → ssh/http-alt 等)、用户名(-p 配合时 UID → 用户名)。先看「默认带名称」与「-n 数字」对同一连接的显示差异:
netstat -t | grep 18000
tcp 0 0 localhost:40512 localhost:18000 ESTABLISHED
tcp 0 0 localhost:18000 localhost:40512 ESTABLISHED
netstat -tn | grep 18000
tcp 0 0 127.0.0.1:40512 127.0.0.1:18000 ESTABLISHED
tcp 0 0 127.0.0.1:18000 127.0.0.1:40512 ESTABLISHED
端口名的翻译数据库是 /etc/services(由 netbase 包提供),其中 ssh 对应 22、http-alt 对应 8080;而 8000 在 Ubuntu 22.04 的 /etc/services 中没有条目(实测 grep "8000/" /etc/services 返回 rc=1),所以 8000 无论加不加 -n 都显示数字。用 8080 做一组 2×2 对照,最能说明问题:
python3 -m http.server 8080 --bind 127.0.0.1 >/dev/null 2>&1 &
netstat -tl | grep http-alt
tcp 0 0 localhost:http-alt 0.0.0.0:* LISTEN
netstat -tln | grep http-alt; echo rc=$?
rc=1
netstat -tln | grep 8080
tcp 0 0 127.0.0.1:8080 0.0.0.0:* LISTEN
- 默认模式把 8080 翻译成
http-alt;加了-n之后该端口一律显示数字。 - 想按端口名 grep,必须不带
-n;想按端口号 grep(写脚本时最稳),必须带-n——两种模式互斥,这是脚本判断「端口是否监听」时最常见的踩坑点。
💡 技术拓展:Linux 的名称解析遵循 nsswitch 机制:主机名按
/etc/nsswitch.conf里的hosts:顺序查/etc/hosts、DNS 等;端口名固定查/etc/services;用户名查/etc/passwd。--numeric-hosts、--numeric-ports、--numeric-users三个长选项可以只关闭其中一类解析(例如保留主机名、但端口显示数字)。
3.6 -tuln:服务器排查标配(逐列解读)
-tuln = TCP + UDP + 监听 + 数字,一条命令看全「这台服务器开了哪些端口」,且不做任何名称解析(速度快、结果稳定),是远程排查的标准第一命令:
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 &
netstat -tuln
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State
tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN
tcp 0 0 0.0.0.0:2222 0.0.0.0:* LISTEN
tcp 0 0 0.0.0.0:8001 0.0.0.0:* LISTEN
tcp 0 0 0.0.0.0:8000 0.0.0.0:* LISTEN
tcp 0 0 0.0.0.0:8443 0.0.0.0:* LISTEN
tcp 0 0 127.0.0.1:18000 0.0.0.0:* LISTEN
tcp6 0 0 :::22 :::* LISTEN
tcp6 0 0 :::2222 :::* LISTEN
udp 0 0 127.0.0.1:9998 0.0.0.0:*
逐列解读:
| 列名 | 含义 | 实测解读 |
|---|---|---|
| Proto | 协议 | tcp / tcp6 / udp / udp6 / unix;tcp6 是 IPv6 监听 |
| Recv-Q | 接收队列 | LISTEN 态=还没被 accept 的连接数;ESTABLISHED 态=已收到但应用还没读走的字节数 |
| Send-Q | 发送队列 | LISTEN 态=accept 队列上限(listen backlog);ESTABLISHED 态=已发出但未被对端确认的字节数 |
| Local Address | 本端地址:端口 | 0.0.0.0:22=监听全部 IPv4;127.0.0.1:18000=仅回环可达 |
| Foreign Address | 对端地址:端口 | LISTEN 行固定 0.0.0.0:*;已连接行为对端真实地址 |
| State | 套接字状态 | UDP 无连接,State 列留空 |
127.0.0.1:18000只绑定回环,外部扫描不到;0.0.0.0:8001对所有网卡开放,暴露面完全不同,排查「端口能被外网访问吗」先看这一列。- 22 与 2222 都有 IPv4 + IPv6 两行,是双栈 sshd 的典型形态。
3.7 -p:显示 PID 与进程名
-p(--programs)追加 PID/Program name 列,需要 root 权限才能看到不属于自己的套接字归属:
python3 -m http.server 18000 --bind 127.0.0.1 >/dev/null 2>&1 &
python3 /root/demo/netstat/hold.py 18000 15 >/dev/null 2>&1 &
netstat -tlnp
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN 2423/sshd: /usr/sbi
tcp 0 0 0.0.0.0:2222 0.0.0.0:* LISTEN 2914/sshd: /usr/sbi
tcp 0 0 0.0.0.0:8001 0.0.0.0:* LISTEN 4159/python3
tcp 0 0 0.0.0.0:8000 0.0.0.0:* LISTEN 4158/python3
tcp 0 0 0.0.0.0:8443 0.0.0.0:* LISTEN 4160/python3
tcp 0 0 127.0.0.1:18000 0.0.0.0:* LISTEN 5123/python3
tcp6 0 0 :::22 :::* LISTEN 2423/sshd: /usr/sbi
tcp6 0 0 :::2222 :::* LISTEN 2914/sshd: /usr/sbi
netstat -tnp | grep 18000
tcp 0 0 127.0.0.1:18000 127.0.0.1:40512 TIME_WAIT -
tcp 0 0 127.0.0.1:40520 127.0.0.1:18000 ESTABLISHED 5125/python3
tcp 0 0 127.0.0.1:18000 127.0.0.1:40520 ESTABLISHED 5123/python3
- ESTABLISHED 行两侧都能看到进程号:
5125/python3是客户端(hold.py),5123/python3是服务端(http.server),-tlnp里则能直接看到 18000 的监听者是 5123。 - TIME_WAIT 行的 PID 列是
-:套接字已关闭、进程不存在,内核只保留状态等待超时,无法归属进程(实测印证)。 - 非 root 执行
-p时,别人的套接字 PID 列不会显示(只显示自己的),脚本里要拿全量信息须以 root 运行。
3.8 -a:全部套接字
-a(--all)= 已连接 + 监听 + 各种中间状态,一张表看全 TCP:
python3 -m http.server 18000 --bind 127.0.0.1 >/dev/null 2>&1 &
python3 /root/demo/netstat/hold.py 18000 15 >/dev/null 2>&1 &
netstat -atn
Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address Foreign Address State
tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN
tcp 0 0 0.0.0.0:2222 0.0.0.0:* LISTEN
tcp 0 0 0.0.0.0:8001 0.0.0.0:* LISTEN
tcp 0 0 0.0.0.0:8000 0.0.0.0:* LISTEN
tcp 0 0 0.0.0.0:8443 0.0.0.0:* LISTEN
tcp 0 0 127.0.0.1:18000 0.0.0.0:* LISTEN
tcp 0 0 127.0.0.1:18000 127.0.0.1:40512 TIME_WAIT
tcp 0 0 127.0.0.1:18000 127.0.0.1:40528 ESTABLISHED
tcp 0 0 127.0.0.1:40528 127.0.0.1:18000 ESTABLISHED
tcp 0 1 172.17.0.2:39868 192.0.2.1:80 SYN_SENT
tcp 0 0 127.0.0.1:8000 127.0.0.1:48644 TIME_WAIT
tcp 0 0 127.0.0.1:18000 127.0.0.1:40520 TIME_WAIT
tcp6 0 0 :::22 :::* LISTEN
tcp6 0 0 :::2222 :::* LISTEN
这一张表同时出现四种状态,可读性最好:LISTEN(服务就位)、ESTABLISHED(连接存活)、TIME_WAIT(刚关闭的残留)、SYN_SENT(正在向 192.0.2.1:80 发起连接尚未得到应答,Send-Q 还挂着 1 字节未发出的 SYN 数据)。排查「连接异常」时 -atn 通常是起点。
3.9 -s:协议统计(SNMP 视角)
-s(--statistics)按协议输出内核计数器,看的是累计值而非瞬时状态,适合巡检与容量判断。先制造一点流量再统计:
python3 -m http.server 18000 --bind 127.0.0.1 >/dev/null 2>&1 &
curl -s http://127.0.0.1:18000/ >/dev/null
netstat -s | head -46
Ip:
Forwarding: 1
8807 total packets received
0 forwarded
0 incoming packets discarded
8788 incoming packets delivered
9187 requests sent out
2 dropped because of missing route
OutTransmits: 9187
Icmp:
559 ICMP messages received
30 input ICMP message failed
ICMP input histogram:
destination unreachable: 53
timeout in transit: 131
echo requests: 157
echo replies: 218
698 ICMP messages sent
0 ICMP messages failed
ICMP output histogram:
destination unreachable: 22
echo requests: 519
echo replies: 157
IcmpMsg:
InType0: 218
InType3: 53
InType8: 157
InType11: 131
OutType0: 157
OutType3: 22
OutType8: 519
Tcp:
236 active connection openings
166 passive connection openings
15 failed connection attempts
10 connection resets received
0 connections established
8105 segments received
7782 segments sent out
26 segments retransmitted
0 bad segments received
127 resets sent
Udp:
126 packets received
16 packets to unknown port received
0 packet receive errors
输出节选(实测首部,Udp 段在此截断)。重点行解读:
- Ip 段:
8807 total packets received收包总数;0 incoming packets discarded网卡层无丢包;2 dropped because of missing route因缺路由丢弃 2 个(对外探测未达目标的正常残留)。 - Tcp 段:
236 active connection openings主动发起次数;15 failed connection attempts连接失败次数(目标不可达/超时);10 connection resets received收到 RST(对端拒绝或强制断开);26 segments retransmitted重传报文段——持续增长说明链路质量差。 - Udp 段:
16 packets to unknown port received收到发往未监听端口的 UDP(会回 ICMP port unreachable);0 packet receive errors无接收错误。
丢弃类计数器可以用 grep 定向抽查(实测):
netstat -s | grep -iE "listen|overflow|drop|buffer errors|failed" | head -16
2 dropped because of missing route
30 input ICMP message failed
0 ICMP messages failed
15 failed connection attempts
0 receive buffer errors
0 send buffer errors
receive/send buffer errors 是 UDP 因 socket 缓冲区不足而丢包的专用计数,为 0 说明无 UDP 丢包压力。TCP 的 accept 队列溢出计数(ListenOverflows/ListenDrops)属于 TcpExt 段,内核只输出非零计数器——本机无溢出,所以这两项不出现;TcpExt 段首部实测如下:
netstat -s | grep -A12 "^TcpExt:" | head -14
TcpExt:
190 TCP sockets finished time wait in fast timer
166 delayed acks sent
1 delayed acks further delayed because of locked socket
Quick ack mode was activated 2 times
885 packet headers predicted
1123 acknowledgments not containing data payload received
1251 predicted acknowledgments
TCPLostRetransmit: 3
TCPTimeouts: 24
TCPLossProbes: 2
TCPBacklogCoalesce: 6
TCPDSACKOldSent: 2
巡检口诀:segments retransmitted、TCPSynRetrans、TCPTimeouts 增长快 = 网络差或对端慢;ListenOverflows/ListenDrops 非零 = 应用 accept 太慢、要调大 backlog。
3.10 -r:路由表(与 route 对照)
-r(--route)显示内核路由表,-rn 是数字形式,与同属 net-tools 的 route -n 输出几乎一致(仅 MSS/Window/irtt 与 Metric/Ref/Use 两类辅助列不同):
netstat -r
Kernel IP routing table
Destination Gateway Genmask Flags MSS Window irtt Iface
default 172.17.0.1 0.0.0.0 UG 0 0 0 eth0
172.17.0.0 0.0.0.0 255.255.0.0 U 0 0 0 eth0
netstat -rn
Kernel IP routing table
Destination Gateway Genmask Flags MSS Window irtt Iface
0.0.0.0 172.17.0.1 0.0.0.0 UG 0 0 0 eth0
172.17.0.0 0.0.0.0 255.255.0.0 U 0 0 0 eth0
route -n
Kernel IP routing table
Destination Gateway Genmask Flags Metric Ref Use Iface
0.0.0.0 172.17.0.1 0.0.0.0 UG 0 0 0 eth0
172.17.0.0 0.0.0.0 255.255.0.0 U 0 0 0 eth0
Flags 速查:U 路由可用,G 经网关(gateway),H 目标是主机,D 由重定向产生,M 已被重定向修改。实测表两条路由的含义:默认路由 0.0.0.0/0 走网关 172.17.0.1 出 eth0;直连网段 172.17.0.0/16 不经网关直接 eth0 交付。
3.11 -i:接口统计(与 ifconfig 对照)
-i(--interfaces)输出内核接口表,一行一个网卡,列与 ifconfig 的 RX/TX 计数一一对应:
netstat -i
Kernel Interface table
Iface MTU RX-OK RX-ERR RX-DRP RX-OVR TX-OK TX-ERR TX-DRP TX-OVR Flg
eth0 1500 3791 0 0 0 4096 0 0 0 BMRU
lo 65536 5246 0 0 0 5246 0 0 0 LRU
| 列 | 对应 ifconfig 字段 | 含义 |
|---|---|---|
| RX-OK / TX-OK | RX/TX packets | 正常收/发包数 |
| RX-ERR / TX-ERR | errors | 坏包/发送错误 |
| RX-DRP / TX-DRP | dropped | 内核缓冲区不足被丢弃 |
| RX-OVR / TX-OVR | overruns | 超过 FIFO 速率被覆盖丢失 |
| Flg | flags | B=BROADCAST M=MULTICAST R=RUNNING U=UP L=LOOPBACK |
加 -e 后 netstat 直接展开成 ifconfig 同款的长格式(下面实测可与 3.11 的 ifconfig eth0 回显逐字段对照,数值完全一致):
netstat -ie
Kernel Interface table
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 172.17.0.2 netmask 255.255.0.0 broadcast 172.17.255.255
ether fe:7b:dc:56:f2:9d txqueuelen 0 (Ethernet)
RX packets 3791 bytes 9563546 (9.5 MB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 4096 bytes 254340 (254.3 KB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536
inet 127.0.0.1 netmask 255.0.0.0
inet6 ::1 prefixlen 128 scopeid 0x10<host>
loop txqueuelen 1000 (Local Loopback)
RX packets 5246 bytes 29823299 (29.8 MB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 5246 bytes 29823299 (29.8 MB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
ifconfig eth0
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 172.17.0.2 netmask 255.255.0.0 broadcast 172.17.255.255
ether fe:7b:dc:56:f2:9d txqueuelen 0 (Ethernet)
RX packets 3791 bytes 9563546 (9.5 MB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 4096 bytes 254340 (254.3 KB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
结论:netstat -i 是「一眼扫全部接口的丢包计数」,netstat -ie / ifconfig 是「单接口完整信息」,两者数据源相同(/proc/net/dev),数值必然一致。
3.12 -c:连续输出
-c(--continuous)让 netstat 每秒刷新一次、持续输出,直到被 Ctrl+C 打断。实测用 timeout 3 限运行 3 秒,可看到同一表格按秒重复(保持连接稳定时内容一致,状态一变下一秒立即反映):
python3 -m http.server 18000 --bind 127.0.0.1 >/dev/null 2>&1 &
python3 /root/demo/netstat/hold.py 18000 12 >/dev/null 2>&1 &
timeout 3 netstat -ct
Active Internet connections (w/o servers)
Proto Recv-Q Send-Q Local Address Foreign Address State
tcp 0 0 localhost:43822 localhost:18000 ESTABLISHED
tcp 0 0 localhost:18000 localhost:40512 TIME_WAIT
tcp 0 0 localhost:18000 localhost:40536 TIME_WAIT
tcp 0 0 localhost:18000 localhost:40528 TIME_WAIT
tcp 0 0 localhost:8000 localhost:48644 TIME_WAIT
tcp 0 0 localhost:18000 localhost:43822 ESTABLISHED
tcp 0 0 localhost:18000 localhost:40520 TIME_WAIT
输出节选(实测为连续三个逐字相同的每秒快照,此处保留第一块)。-c 常与 grep/tee 搭配做简易实时监控,如 netstat -ct | grep ESTABLISHED;需要更精细的按状态过滤与计时器信息时,改用 ss -ti 更强。
3.13 State 状态全集实测
netstat 的 State 列取值来自 TCP 状态机。同一个演示块里同时造出四种最常见状态:http.server 提供 LISTEN;hold.py 保持一条 ESTABLISHED;close_wait.py 完成一次 HTTP 交互后不关闭套接字(对端已发 FIN,本端应用迟迟不 close → CLOSE_WAIT);curl 短请求结束后服务端作为主动关闭方留下 TIME_WAIT:
python3 -m http.server 18000 --bind 127.0.0.1 >/dev/null 2>&1 &
python3 /root/demo/netstat/hold.py 18000 25 >/dev/null 2>&1 &
python3 /root/demo/netstat/close_wait.py 18000 25 >/dev/null 2>&1 &
curl -s http://127.0.0.1:18000/ >/dev/null
netstat -atn | grep -E "LISTEN|ESTABLISHED|TIME_WAIT|CLOSE_WAIT"
tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN
tcp 0 0 0.0.0.0:2222 0.0.0.0:* LISTEN
tcp 0 0 0.0.0.0:8001 0.0.0.0:* LISTEN
tcp 0 0 0.0.0.0:8000 0.0.0.0:* LISTEN
tcp 0 0 0.0.0.0:8443 0.0.0.0:* LISTEN
tcp 0 0 127.0.0.1:18000 0.0.0.0:* LISTEN
tcp 0 0 127.0.0.1:18000 127.0.0.1:43836 ESTABLISHED
tcp 0 0 127.0.0.1:43848 127.0.0.1:18000 CLOSE_WAIT
tcp 0 0 127.0.0.1:43836 127.0.0.1:18000 ESTABLISHED
tcp 0 0 127.0.0.1:18000 127.0.0.1:40512 TIME_WAIT
tcp 0 0 127.0.0.1:18000 127.0.0.1:40536 TIME_WAIT
tcp 0 0 127.0.0.1:18000 127.0.0.1:40528 TIME_WAIT
tcp 0 0 127.0.0.1:18000 127.0.0.1:43854 TIME_WAIT
tcp 0 0 127.0.0.1:8000 127.0.0.1:41584 TIME_WAIT
tcp 0 0 127.0.0.1:8000 127.0.0.1:48644 TIME_WAIT
tcp 0 0 127.0.0.1:18000 127.0.0.1:43822 TIME_WAIT
tcp 0 0 127.0.0.1:18000 127.0.0.1:40520 TIME_WAIT
tcp6 0 0 :::22 :::* LISTEN
tcp6 0 0 :::2222 :::* LISTEN
四种状态一次集齐,逐一说明:
| State | 出现位置 | 实测对应 | 含义 |
|---|---|---|---|
| LISTEN | 127.0.0.1:18000 → 0.0.0.0:* | http.server 服务端 | 等待连接请求 |
| ESTABLISHED | :18000 ↔ :43836 一对 | hold.py 挂住的连接 | 三次握手完成,可收发数据 |
| CLOSE_WAIT | 127.0.0.1:43848 → :18000 | close_wait.py 客户端 | 对端已关闭、本端应用未调 close |
| TIME_WAIT | 127.0.0.1:18000 → :40512 等多行 | curl 触发的主动关闭方 | 主动关闭后等待 2MSL(Linux 固定 60 秒) |
netstat 可能出现的完整状态集合(man netstat 汇总):ESTABLISHED、SYN_SENT、SYN_RECV、FIN_WAIT1、FIN_WAIT2、TIME_WAIT、CLOSE、CLOSE_WAIT、LAST_ACK、LISTEN、CLOSING、UNKNOWN。判读经验:TIME_WAIT 大量堆积在服务端属于正常(主动关闭方的正常旅程);CLOSE_WAIT 长期堆积则说明本端应用有连接泄漏(忘了 close)。
3.14 Recv-Q / Send-Q 非零解读
Recv-Q/Send-Q 的含义随状态不同而完全不同,实测两组非零场景。
场景一:只 listen 不 accept(accept 队列积压)——LISTEN 行的 Recv-Q=1、Send-Q=2:
python3 /root/demo/netstat/listen_noaccept.py 7777 30 >/dev/null 2>&1 &
python3 /root/demo/netstat/hold.py 7777 28 >/dev/null 2>&1 &
netstat -altn | grep 7777
tcp 1 0 127.0.0.1:7777 0.0.0.0:* LISTEN
tcp 0 0 127.0.0.1:48340 127.0.0.1:7777 ESTABLISHED
tcp 0 0 127.0.0.1:7777 127.0.0.1:48340 ESTABLISHED
- LISTEN 行
Recv-Q=1:已有 1 条完成握手但还没被应用 accept 的连接;Send-Q=2:不是字节数,而是listen(2)时的 backlog 上限。若 Recv-Q 长期顶到 Send-Q,说明应用处理不动、新连接开始排队甚至被丢弃。
场景二:连接建立但应用不读/发不出去(字节队列)——服务端 Recv-Q=127151、客户端 Send-Q=72849:
python3 /root/demo/netstat/noread_server.py 8888 30 >/dev/null 2>&1 &
python3 /root/demo/netstat/send_noread.py 8888 28 >/dev/null 2>&1 &
netstat -altn | grep 8888
tcp 0 0 127.0.0.1:8888 0.0.0.0:* LISTEN
tcp 0 72849 127.0.0.1:40934 127.0.0.1:8888 ESTABLISHED
tcp 127151 0 127.0.0.1:8888 127.0.0.1:40934 ESTABLISHED
netstat -t | grep 8888
tcp 0 72849 localhost:40934 localhost:8888 ESTABLISHED
tcp 127151 0 localhost:8888 localhost:40934 ESTABLISHED
客户端发了 200000 字节、服务端应用一直不读:127151 字节堆在服务端接收缓冲区(Recv-Q),剩下的 72849 字节滞留在客户端发送缓冲区(Send-Q),两个数相加正好约等于发送总量。ESTABLISHED 态下 Recv-Q 持续偏大 = 对端/本端应用读得太慢;Send-Q 持续偏大 = 网络慢或对端不收。
3.15 错误用法与退出码
netstat 对未知参数返回 usage 并以退出码 3 结束(脚本里可用返回值判断参数合法性):
netstat --no-such-option; echo rc=$?
netstat: unrecognized option '--no-such-option'
usage: netstat [-vWeenNcCF] [<Af>] -r netstat {-V|--version|-h|--help}
netstat [-vWnNcaeol] [<Socket> ...]
netstat { [-vWeenNac] -i | [-cnNe] -M | -s [-6tuw] }
(后续完整 usage 清单与 2.2 节 --help 回显逐字一致,此处节选)
rc=3
netstat -u 在无结果时返回 0(见 3.3),因此「空输出 + rc=0」不代表异常,脚本判断应以输出内容为准;而参数错误固定返回 3。
3.16 技术拓展:netstat vs ss 命令映射
net-tools(netstat/ifconfig/route/arp)读取 /proc 伪文件实现,2001 年起基本停止功能维护;iproute2(ss/ip)走内核 netlink 接口,数据一次取全、支持过滤语法,性能与可维护性都更好。新脚本建议直接用 ss,两者常用组合对应关系如下(ss 篇有逐参数实测):
| 用途 | netstat 写法 | ss 等价写法 |
|---|---|---|
| 监听端口总览(TCP+UDP,数字) | netstat -tuln | ss -tuln |
| TCP 监听 + 进程 | netstat -tlnp | ss -tlnp |
| 已建立连接(数字) | netstat -ant | ss -ant |
| 按状态过滤 | netstat -ant | grep TIME_WAIT | ss state time-wait |
| 按目标地址过滤 | netstat -ant | grep 127.0.0.1 | ss -tn dst 127.0.0.1 |
| 协议统计 | netstat -s | ss -s(摘要)/ nstat(计数器) |
| 路由表 | netstat -rn | ip route |
| 接口统计 | netstat -i | ip -s link |
| 强制断开连接 | 无对应功能 | ss -K dst <IP> |
数据源差异是本质:netstat 逐个读 /proc/net/* 文本文件(连接数大时开销线性放大),ss 通过 netlink 一次性取内核套接字表,还可以用 state、dst、sport 等表达式在内核侧完成过滤——这也是本文 3.12/3.14 场景在 ss 下的更优解法。
四、实战示例
4.1 确认服务是否在监听
最常用的一条:服务起没起、绑在哪个地址、对不对端口,一行看清(实测):
python3 -m http.server 18000 --bind 127.0.0.1 >/dev/null 2>&1 &
netstat -tln | grep 18000
tcp 0 0 127.0.0.1:18000 0.0.0.0:* LISTEN
有输出即监听成功;127.0.0.1 说明只对内开放,改成 0.0.0.0 行才是全网卡监听。
4.2 定位端口被哪个进程占用
「18000 被谁占了?能不能杀?」——-p 直接给出 PID:
netstat -tlnp | grep 18000
tcp 0 0 127.0.0.1:18000 0.0.0.0:* LISTEN 5353/python3
拿到 PID 后即可 kill 5353 释放端口。TIME_WAIT 残留不占进程、不需要 kill,等 60 秒自动消失(见 3.7 实测)。
4.3 连接状态分布统计
对某端口的连接按状态计数,快速判断负载形态(压测时 ESTABLISHED 应约等于并发数):
python3 /root/demo/netstat/hold.py 18000 20 >/dev/null 2>&1 &
netstat -ant | grep 18000 | tr -s " " | cut -d" " -f6 | sort | uniq -c
2 ESTABLISHED
1 LISTEN
netstat -t | grep 18000 | tr -s " " | cut -d" " -f4
localhost:18000
localhost:53610
第一条统计出「2 条已建立 + 1 个监听」;第二条取 Local Address 列,可进一步区分服务端(:18000)与客户端(随机端口 53610)视角。
4.4 网络质量巡检三件套
巡检顺序建议:先 -s 看计数器有没有恶化,再 -i 看接口有没有丢包,最后 -rn 确认路由没有被改(实测回显):
netstat -s | grep -E "segments retransmitted|failed connection|resets received"
26 failed connection attempts
16 connection resets received
40 segments retransmitted
netstat -i
Kernel Interface table
Iface MTU RX-OK RX-ERR RX-DRP RX-OVR TX-OK TX-ERR TX-DRP TX-OVR Flg
eth0 1500 3863 0 0 0 4178 0 0 0 BMRU
lo 65536 5496 0 0 0 5496 0 0 0 LRU
netstat -rn
Kernel IP routing table
Destination Gateway Genmask Flags MSS Window irtt Iface
0.0.0.0 172.17.0.1 0.0.0.0 UG 0 0 0 eth0
172.17.0.0 0.0.0.0 255.255.0.0 U 0 0 0 eth0
三项实测均健康:重传占比低、接口零丢包零错包、默认路由未变。把三组数字与上次巡检对比(差值趋势比绝对值更有意义)即可作为日常网络巡检的最小集。
五、注意事项与常见问题
Q1:为什么别人的 netstat 里 8000 显示 http-alt,我的却一直是数字?
实测 Ubuntu 22.04 的 /etc/services 中 http-alt 对应的是 8080(grep -nE "^(ssh|http-alt)" /etc/services 输出 263:http-alt 8080/tcp webcache),而 8000 没有任何条目(grep "8000/" /etc/services 返回 rc=1)。所以 Ubuntu 22.04 上 8000 永远显示数字;只有 8080 这类有登记的端口才会翻译成 http-alt。另外,若系统缺少 /etc/services(netbase 包提供),所有端口都显示数字,apt-get install netbase 即可补齐。
Q2:netstat -tlnp 看不到别的用户的进程号?
-p 依赖读取 /proc/<pid>/fd,只能归属自己有权查看的进程。要以 root 运行才能看到全部 PID/Program name;TIME_WAIT/CLOSE_WAIT 等已断开或无属主的行 PID 列显示 -(见 3.7 实测),属正常现象。
Q3:服务明明在跑,为什么 netstat 看不到?
默认输出是 w/o servers(不含 LISTEN,见 3.1),必须加 -l(只看监听)或 -a(全量)。另外服务若只绑 127.0.0.1,从外部用 0.0.0.0 去匹配自然找不到,先看清 Local Address 列。
Q4:大量 TIME_WAIT 正常吗?会耗尽端口吗?
TIME_WAIT 是主动关闭方的正常状态,Linux 固定 60 秒后释放。高并发短连接服务端出现大量 TIME_WAIT 属正常;若想缓解,客户端侧开启连接复用(HTTP keep-alive)、或调整 net.ipv4.tcp_tw_reuse 才是正路,不要盲目 kill。
Q5:CLOSE_WAIT 很多怎么办?
CLOSE_WAIT 是「对端已关、本端没关」,只能由应用调用 close() 消除,内核参数对它无效。持续堆积 = 代码存在连接泄漏(没 close、连接池泄漏),用 netstat -antp | grep CLOSE_WAIT 结合 PID 定位泄漏进程。
Q6:netstat 执行很慢怎么优化?
默认会对每个地址做 DNS 反解、查用户名,网络不佳时很卡。一律加 -n 跳过解析;脚本中固定用 netstat -an。若对性能有更高要求(万级连接),改用走 netlink 的 ss(见 3.16 节)。
Q7:netstat -u 输出空、退出码却是 0?
UDP 无连接,默认视图过滤掉了未连接套接字(见 3.3 实测),空输出 + rc=0 是正常现象;看 UDP 监听用 netstat -alun。
Q8:-c 怎么停下来?管道里怎么用?
-c 每秒刷新直到 Ctrl+C;放在管道里建议包一层 timeout(如本文实测的 timeout 3 netstat -ct),否则永远不会自然退出,脚本会挂死。
六、参考链接
- netstat(8) 手册(man7 上游归档):https://man7.org/linux/man-pages/man8/netstat.8.html
- net-tools 项目主页:https://sourceforge.net/projects/net-tools/
- /etc/services 端口名数据库(IANA 注册端口):https://www.iana.org/assignments/service-names-port-numbers/service-names-port-numbers.xhtml
- Linux TCP 状态机说明(RFC 9293,含 TIME_WAIT 定义):https://www.rfc-editor.org/rfc/rfc9293
- iproute2 ss 手册(netstat 替代方案):https://man7.org/linux/man-pages/man8/ss.8.html