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)实测通过。

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

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-OKRX/TX packets正常收/发包数
RX-ERR / TX-ERRerrors坏包/发送错误
RX-DRP / TX-DRPdropped内核缓冲区不足被丢弃
RX-OVR / TX-OVRoverruns超过 FIFO 速率被覆盖丢失
FlgflagsB=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出现位置实测对应含义
LISTEN127.0.0.1:18000 → 0.0.0.0:*http.server 服务端等待连接请求
ESTABLISHED:18000 ↔ :43836 一对hold.py 挂住的连接三次握手完成,可收发数据
CLOSE_WAIT127.0.0.1:43848 → :18000close_wait.py 客户端对端已关闭、本端应用未调 close
TIME_WAIT127.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 -tulnss -tuln
TCP 监听 + 进程netstat -tlnpss -tlnp
已建立连接(数字)netstat -antss -ant
按状态过滤netstat -ant | grep TIME_WAITss state time-wait
按目标地址过滤netstat -ant | grep 127.0.0.1ss -tn dst 127.0.0.1
协议统计netstat -sss -s(摘要)/ nstat(计数器)
路由表netstat -rnip route
接口统计netstat -iip -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),否则永远不会自然退出,脚本会挂死。

六、参考链接