三亩地 三亩地SAN MU DI · CODE DIARY
ARTICLE DETAIL

日记详情

真实记录编程学习的某一天,欢迎挑你感兴趣的翻一翻。

Linux网络连接状态排查:从netstat到ss的运维实战指南

Linux网络连接状态排查:从netstat到ss的运维实战指南

1. 网络连接状态:运维的“听诊器”

在Linux系统运维和开发工作中,网络连接状态是排查问题、分析性能、保障安全的第一手资料。无论是服务器响应变慢、端口冲突,还是怀疑存在异常连接或潜在安全风险,第一时间查看网络连接状态,就像医生拿起听诊器一样,是进行“诊断”的基础操作。对于系统管理员、后端开发、安全工程师乃至任何需要与服务器打交道的技术人员来说,熟练使用相关命令是必备技能。

很多人可能只知道一个netstat,或者用过ss但不明就里。实际上,Linux提供了从经典到现代的一系列工具,如netstatsslsof乃至直接查看/proc虚拟文件系统。它们各有侧重,有的信息全面但稍显陈旧,有的速度极快且信息详尽,还有的能从进程视角看问题。理解这些工具的核心原理、输出列的含义以及组合使用技巧,能让你在遇到网络问题时,迅速定位到是哪个进程、通过哪个端口、与哪台远程主机建立了何种状态的连接,从而高效地解决问题。本文将从一个资深运维的角度,带你彻底搞懂如何查看和分析Linux系统的网络连接状态。

2. 工具全景:从 netstat 到 /proc

在深入每个命令之前,我们有必要先了解一下工具箱里都有什么,以及为什么会有这么多选择。这背后其实是Linux网络栈和工具发展的一个缩影。

2.1 经典之选:netstat

netstat(network statistics)是一个历史悠久的网络工具,属于net-tools软件包。它的优点是功能全面、输出直观,几乎在所有Linux发行版上都预装或易于安装。它可以显示路由表、网络接口统计信息、多播成员以及最重要的——网络连接状态。

然而,netstat在现代Linux系统上有一个明显的缺点:性能。它通过直接读取/proc/net/tcp/proc/net/udp等文件来获取信息,并且在解析这些文件时,为了将IP地址和端口号解析成可读的服务名(如将22端口显示为ssh),可能需要频繁进行DNS反向解析和/etc/services文件查找,这在连接数巨大时(例如数万并发)会非常缓慢,甚至可能拖慢系统。

注意:尽管存在性能问题,netstat的语法和输出格式非常经典,许多脚本和运维人员的使用习惯都基于它。学习netstat有助于理解网络连接状态的基本概念,这些概念在其他工具中是通用的。

2.2 现代替代:ss

ss(socket statistics)是iproute2软件包的一部分,旨在取代netstat。它直接从内核空间(通过netlink接口或tcp_diag模块)获取socket信息,速度极快,即使面对数十万连接也能瞬间响应。此外,ss显示的信息通常比netstat更详细,特别是TCP内部状态(如发送/接收队列大小、拥塞控制算法等)。

可以这么说,ss是现代Linux系统上查看网络连接状态的首选和推荐工具。它的语法与netstat大部分兼容,学习成本低,但能力更强。

2.3 进程视角:lsof

lsof(list open files)的核心理念是“在Linux中,一切皆文件”。网络连接(socket)也是一种特殊的文件描述符。因此,lsof可以从进程的角度,列出其打开的所有文件,其中就包括网络连接。

lsof的强大之处在于它能精确地将端口或连接关联到具体的进程ID(PID)和进程名,并且能显示进程的用户等信息。当你需要回答“哪个进程占用了8080端口?”这类问题时,lsof往往是最直接的工具。

2.4 终极源头:/proc 文件系统

/proc是一个虚拟文件系统,它提供了访问内核内部数据结构的接口。网络连接信息就存放在/proc/net/目录下(如/proc/net/tcp/proc/net/udp)。netstatss本质上都是对这些数据进行解析和美化输出。

直接查看/proc文件内容比较原始(IP和端口都以十六进制显示),可读性差,一般不用于手动排查。但它揭示了信息的本质来源,并且在某些极端环境(工具缺失)下,可以直接通过catgrep这些命令获取最原始的数据。

工具选型速查表:

工具所属套件主要特点适用场景性能
netstatnet-tools功能全面,输出经典,易读学习概念,简单排查,老系统较差,连接数多时慢
ssiproute2速度极快,信息详细,现代首选生产环境排查,高性能需求极佳
lsoflsof进程关联性强,能查所有打开文件定位占用端口的进程较好
/proc内核信息源头,原始数据理解原理,工具缺失时的备用方案直接读取,无额外开销

3. 核心命令详解与实战用法

了解了工具全景,我们进入实战环节。我将以ss命令为主,对比讲解netstat,并穿插lsof的特定用法,因为ss是当前事实上的标准。

3.1 ss 命令:语法与常用选项

ss的基本语法是:ss [选项] [过滤表达式]

常用选项组合与解释:

  • -t:显示TCP套接字。
  • -u:显示UDP套接字。
  • -l:仅显示监听(LISTEN)状态的套接字。这是查看系统开放了哪些端口的常用方式。
  • -a:显示所有状态的套接字(包括监听、已建立、等待关闭等)。
  • -n:以数字形式显示地址和端口,不进行DNS反向解析和服务名查找强烈建议始终加上-n选项,可以大幅提升命令执行速度,避免因DNS问题导致命令卡住。
  • -p:显示使用该套接字的进程信息(PID和进程名)。需要root权限才能查看其他用户的进程信息。
  • -4:仅显示 IPv4 套接字。
  • -6:仅显示 IPv6 套接字。
  • -s:显示套接字使用情况的统计摘要(总连接数、TCP各状态连接数等)。
  • -o:显示TCP定时器信息(如保活时间)。
  • -e:显示套接字的扩展详细信息(如用户ID、inode等)。
  • -i:显示TCP内部信息(如拥塞窗口、rtt等)。

最常用的组合:

  • ss -tunlp:查看所有TCP和UDP的监听端口,并显示进程信息。这是查看本机开放了哪些服务的黄金命令。
  • ss -tan:查看所有TCP连接(包括监听和已建立),以数字格式显示。
  • ss -tan state ESTABLISHED:使用过滤表达式,仅显示已建立的TCP连接。

3.2 输出列深度解析

执行ss -tunlpss -tan,你会看到类似下面的输出。理解每一列的含义至关重要。

Netid State Recv-Q Send-Q Local Address:Port Peer Address:Port tcp LISTEN 0 128 *:22 *:* users:(("sshd",pid=1234,fd=3)) tcp ESTAB 0 0 192.168.1.100:22 192.168.1.50:54321
  • Netid: 套接字类型。tcp,udp,raw等。
  • State: 套接字状态。这是分析连接健康度的关键。
    • LISTEN: 服务端套接字正在监听,等待连接。
    • ESTABLISHED: 连接已成功建立,正在进行数据传输。
    • SYN-SENT: 本地应用发送了SYN包,正在等待对方的SYN-ACK(TCP三次握手第一步)。
    • SYN-RECV: 收到了对方的SYN包,并回复了SYN-ACK,等待对方的ACK(TCP三次握手第二步)。
    • FIN-WAIT-1: 本地已发送FIN包,请求关闭连接,等待对方的ACK或FIN。
    • CLOSE-WAIT: 对方已关闭连接(发送了FIN),本地正在等待应用层处理完数据后关闭。
    • TIME-WAIT: 连接已关闭,等待足够的时间(2MSL)以确保网络中所有旧报文都消失。大量TIME-WAIT连接是正常现象,通常意味着你的服务作为客户端主动关闭了大量短连接
  • Recv-QSend-Q: 这两个队列的大小是诊断网络瓶颈的重要指标。
    • 对于监听套接字(LISTEN)
      • Recv-Q: 当前已完成三次握手(SYN_RECV状态)但尚未被应用层accept()取走的连接队列长度。
      • Send-Q: 监听队列的最大长度(即backlog参数,如somaxconn控制)。
    • 对于已建立的套接字(ESTABLISHED等)
      • Recv-Q: 内核中已接收但尚未被应用层read()取走的数据量(字节)。
      • Send-Q: 内核中已发送但尚未收到对方确认(ACK)的数据量(字节)。
    • 如果Recv-Q持续很大,可能表示应用进程处理不过来,卡住了。
    • 如果Send-Q持续很大且不减少,可能表示网络拥塞或对端接收缓慢。
  • Local Address:Port: 本地绑定的IP和端口。*表示绑定在所有接口(0.0.0.0),127.0.0.1表示只绑定在本地环回。
  • Peer Address:Port: 对端(远程)的IP和端口。对于监听套接字,这里是*:*
  • 最后一列(使用-p时): 关联的进程信息,包括进程名和PID。这是定位问题的关键。

3.3 netstat 命令对比与迁移

如果你熟悉netstat,可以这样迁移到ss

功能netstat 命令ss 等效命令说明
所有TCP监听端口netstat -tlnpss -tlnp几乎一致
所有连接(含监听)netstat -tanss -tan几乎一致
显示进程信息netstat -tunlpss -tunlp注意ss-u单独表示UDP
统计摘要netstat -sss -sss -s的输出更简洁
按状态过滤netstat -tan | grep ESTABss -tan state ESTABLISHEDss的过滤更原生高效

一个重要的区别netstat-a选项默认包含监听和所有非监听连接。而ss-a也是类似,但ss提供了更强大的过滤表达式,例如ss state established

3.4 lsof 的精准定位

ss -tunlp无法直接显示进程,或者你想从端口反查进程时,lsof是利器。

  • 查看谁在监听特定端口

    lsof -i :8080

    这会列出所有打开8080端口的进程。-i选项用于指定网络连接。

  • 查看某个进程打开的所有网络连接

    lsof -i -a -p <PID>

    或者更简单:lsof -i -p <PID>

  • 查看所有TCP监听端口

    lsof -iTCP -sTCP:LISTEN

    这相当于ss -tlnp,但输出格式不同。

lsof输出的信息非常丰富,包括命令、PID、用户、FD(文件描述符)、类型、设备、大小、节点名等。对于网络连接,我们主要关注COMMAND,PID,USER,FD,TYPE,DEVICE,NODE NAME(其中包含了IP:端口信息)。

4. 高级过滤与状态分析实战

ss的强大之处在于其基于表达式的过滤能力,可以让你像数据库查询一样精准定位连接。

4.1 按连接状态过滤

TCP连接状态是分析问题的核心。你可以使用state关键字。

  • 查看所有已建立的连接

    ss -tan state established
  • 查看所有等待关闭的连接(TIME-WAIT, CLOSE-WAIT)

    ss -tan state time-wait ss -tan state close-wait

    也可以组合查看:

    ss -tan state time-wait,close-wait
  • 查看所有非监听状态的连接

    ss -tan state connected

    connected是一个宏,代表所有已建立和正在关闭的状态(不包括listen,closed等)。

4.2 按地址和端口过滤

  • 查看连接到特定远程主机的连接

    ss -tan dst 192.168.1.200
  • 查看从特定本地端口发起的连接

    ss -tan sport = :54321
  • 查看连接到特定远程端口的连接

    ss -tan dport = :80
  • 组合过滤:查看本地80端口的所有已建立连接。

    ss -tan state established dport = :80

4.3 诊断案例:服务器连接数异常分析

假设监控报警,某台Web服务器(Nginx)的TCP连接数异常增高。你可以按以下步骤排查:

  1. 总体概览:首先用ss -s看统计摘要,确认TCP连接总数是否真的异常,以及各状态分布。

    ss -s

    关注TotalTCP部分的数字。

  2. 定位监听端口:确认Nginx监听的端口(假设是80和443)状态。

    ss -tlnp | grep -E ‘:(80\|443)’

    检查Recv-Q是否堆积。如果Recv-Q很大,说明有很多连接已握手完成但Nginx来不及accept(),可能需要调整net.core.somaxconn内核参数或Nginx的backlog配置。

  3. 分析已建立连接:查看所有到80端口的已建立连接,看看来自哪些IP。

    ss -tan state established dport = :80 | head -20

    如果发现大量连接来自少数几个IP,可能是爬虫或攻击。可以进一步用awk统计IP出现次数。

  4. 分析异常状态:查看是否有大量异常状态连接,如SYN-RECV(半连接)。

    ss -tan state syn-recv

    大量SYN-RECV可能是SYN Flood攻击的迹象。此时需要结合netstat -s | grep -i listen(或ss -s中的SYN-RECV计数)和系统日志进一步判断。

  5. 关联进程:如果怀疑不是Nginx,而是其他进程建立了大量连接,可以用ss -tanp查看所有连接的进程信息,或者用lsof -iTCP来交叉验证。

4.4 实操心得:关于 TIME-WAIT 的误解与处理

很多运维新手看到服务器上有成千上万的TIME-WAIT连接就非常紧张,认为这耗尽了资源。实际上,TIME-WAIT状态是TCP协议为了保证可靠关闭而设计的,每个TIME-WAIT连接只占用一个四元组(源IP、源端口、目的IP、目的端口)和少量内存(约1KB左右)。对于现代服务器来说,几万个TIME-WAIT连接通常不是问题。

真正需要关注的是端口耗尽的可能性。如果服务器作为客户端,频繁地用同一个本地端口段向同一个远程服务(相同IP和端口)发起短连接,可能会因为本地端口来不及回收而耗尽。这时可以考虑以下方案:

  1. 启用端口复用和快速回收(需谨慎评估,可能违反RFC):

    # 允许将TIME-WAIT套接字重新用于新的TCP连接 sysctl -w net.ipv4.tcp_tw_reuse=1 # 快速回收TIME-WAIT套接字(在NAT环境下可能有问题) # sysctl -w net.ipv4.tcp_tw_recycle=1 # 该参数在较新内核中已移除

    注意tcp_tw_recycle在存在NAT的网络中可能导致问题,且在内核4.12之后已被移除。生产环境建议只开启tcp_tw_reuse,并充分测试。

  2. 调整本地端口范围

    sysctl -w net.ipv4.ip_local_port_range="1024 65535"

    这扩大了可用临时端口的数量。

  3. 优化应用:使用连接池,避免频繁创建和关闭短连接,这是最根本的解决方案。

5. 脚本化监控与自动化排查

手动敲命令适合临时排查,但对于常态化监控和自动化运维,我们需要脚本。

5.1 监控监听端口变化

一个简单的脚本,记录当前监听端口,并与之前记录对比,发现新增或减少的端口,可用于安全监控。

#!/bin/bash # 保存当前监听端口列表 ss -tunlp | grep LISTEN | sort > /tmp/current_listen_ports.txt # 如果存在历史记录,则对比 if [ -f /tmp/last_listen_ports.txt ]; then echo “=== 新增的监听端口 ==” comm -13 /tmp/last_listen_ports.txt /tmp/current_listen_ports.txt echo “=== 消失的监听端口 ==” comm -23 /tmp/last_listen_ports.txt /tmp/current_listen_ports.txt fi # 更新历史记录 mv /tmp/current_listen_ports.txt /tmp/last_listen_ports.txt

5.2 统计各状态的连接数

ss -s的输出进行解析,提取关键指标,便于接入监控系统(如Zabbix, Prometheus)。

#!/bin/bash # 提取ss -s输出中的TCP连接数统计 ss_stats=$(ss -s | grep -A 10 “^TCP:”) total_tcp=$(echo “$ss_stats” | grep ‘estab’ | awk ‘{print $4}’) time_wait=$(echo “$ss_stats” | grep ‘timewait’ | awk ‘{print $4}’ | sed ‘s/,//’) close_wait=$(echo “$ss_stats” | grep ‘close-wait’ | awk ‘{print $4}’ | sed ‘s/,//’) echo “TCP_TOTAL $total_tcp” echo “TCP_TIME_WAIT $time_wait” echo “TCP_CLOSE_WAIT $close_wait”

5.3 查找连接数最多的远程IP

当怀疑有单IP攻击或异常爬虫时,这个脚本非常有用。

#!/bin/bash # 统计连接到本地80端口的ESTABLISHED连接,按远程IP计数 ss -tan state established dport = :80 | awk ‘{print $5}’ | cut -d: -f1 | sort | uniq -c | sort -rn | head -20

这个命令管道做了以下几件事:

  1. ss -tan state established dport = :80:获取所有到80端口的已建立连接。
  2. awk ‘{print $5}’:提取第五列(Peer Address:Port)。
  3. cut -d: -f1:以冒号分隔,取第一部分(IP地址)。
  4. sort:排序,为uniq -c做准备。
  5. uniq -c:统计每个IP出现的次数。
  6. sort -rn:按次数反向数字排序(从大到小)。
  7. head -20:显示前20个。

5.4 常见问题排查速查表

现象/问题可能原因排查命令与思路
“Address already in use”(端口被占用)1. 其他进程正在监听该端口。
2. 该端口处于TIME-WAIT状态,且未启用SO_REUSEADDR
1.ss -tlnp | grep :<端口号>lsof -i :<端口号>查找占用进程。
2.ss -tan state time-wait | grep :<端口号>查看是否有TIME-WAIT连接。
服务无法连接,但端口在监听1. 防火墙(iptables, firewalld)阻止。
2. 服务只绑定在127.0.0.1(本地环回)。
3. 应用层问题(如进程僵死)。
1.ss -tlnp检查Local Address0.0.0.0还是127.0.0.1
2. 检查防火墙规则。
3. 检查进程状态和日志。
大量SYN-RECV状态连接1. SYN Flood攻击。
2. 客户端发送SYN后崩溃或网络问题。
3. 服务器backlog队列满,且未及时accept()
1.netstat -s | grep -i listen查看被丢弃的SYN包数量。
2. 检查服务器负载和ss -tlnRecv-Q
3. 考虑启用tcp_syncookies
大量CLOSE-WAIT状态连接应用层Bug的典型标志!本地应用没有及时调用close()关闭socket。1.ss -tanp state close-wait定位是哪个进程。
2. 检查该进程的代码,确认socket资源是否被正确释放。
Send-QRecv-Q持续很大1. 网络拥塞或对端处理慢(Send-Q大)。
2. 本地应用处理不过来(Recv-Q大)。
1. 检查网络状况(延迟、丢包)。
2. 检查应用进程的CPU、IO状态,看是否有阻塞。
连接数缓慢增长不释放1. 连接泄漏(应用未关闭连接)。
2. 长连接场景,属于正常。
1. 定期执行ss -s监控趋势。
2. 使用ss -tanplsof -p <PID>分析特定进程的连接生命周期。

掌握这些命令和脚本,你就能像拥有X光透视眼一样,看清Linux系统内部网络通信的实时状况。从简单的端口查看到复杂的性能瓶颈分析,这套方法论覆盖了绝大部分日常运维和故障排查场景。记住,ss是你的主力工具,lsof是精准的手术刀,而理解TCP状态机则是你的核心诊断理论。多练,多思考,下次遇到网络问题,你就能从容应对了。

← 返回列表