尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

netstat实战指南:从端口占用定位到TCP状态排障

netstat实战指南:从端口占用定位到TCP状态排障 1. 端口被占用时的第一反应一条命令定位真凶如果你和我一样常年跟服务部署、接口联调打交道一定遇到过这种场景代码改完信心满满地重启服务结果控制台直接抛出一句Port 8080 was already in use。脑袋里瞬间冒出三个问号谁占的为什么不释放我该去打谁这时候netstat -ano就是那个帮你把真凶揪出来的第一把钥匙。拿 Windows 举例你只需要打开命令行敲下这行netstat -ano | findstr :8080输出里会出现类似这样的内容TCP 0.0.0.0:8080 0.0.0.0:0 LISTENING 8891短短一行信息量其实非常大。TCP是协议类型0.0.0.0:8080表示本机所有网卡地址都在 8080 端口上监听0.0.0.0:0是外部地址为 0 表示还没建立连接LISTENING是当前连接状态最后那个8891就是占用这个端口的进程 PID。拿到 PID 之后再敲一句tasklist | findstr 8891立刻能知道是哪个进程霸占着端口。如果是你自己跑的服务残留进程taskkill /PID 8891 /F直接结束掉世界瞬间清净。1.1 为什么是 -ano 而不是 -a这是很多新手最容易忽略的细节。netstat单独敲下去只显示已经建立的连接那些正在监听的端口、正在握手的半连接一概看不到。加上-a才是查看所有连接和监听端口的完整视图。-n的作用是让 netstat 以纯数字形式显示地址和端口不解析域名。很多人觉得-n加不加无所谓其实这个参数在实战中特别关键。如果你不加-nnetstat 会把 IP 反解成主机名而这个反解过程需要走 DNS 查询。一旦 DNS 服务器响应慢或者目标地址在公网解析不到命令会长时间卡住看起来就像死机了一样。加了-n结果立刻秒出端口号也一目了然。-o是 Windows 下特有的参数作用是显示每个连接对应的进程 PID。没有它你只能看到端口被占用却不知道是谁占的排查链路直接断掉一半。所以-a -n -o这三个参数组合在一起就是 Windows 下排查端口问题的黄金组合看全量连接、跳过域名解析、直达进程身份。1.2 输出五列信息到底该怎么读netstat 的输出列名在不同系统上略有差异但 Windows 下基本是固定的五列协议、本地地址、外部地址、状态、PID。本地地址这一列有个容易看懵的地方0.0.0.0:8080和127.0.0.1:8080虽然端口号一样但含义完全不同。0.0.0.0表示监听在所有网卡上局域网内其他机器可以通过你的内网 IP 访问这个服务127.0.0.1则表示只监听在环回地址上只有本机能访问。排查端口冲突时这两种情况都要算作端口被占用但如果你需要让局域网同事访问你的服务却看到监听地址是127.0.0.1那问题就不是端口冲突而是服务配置本身就绑定错了网卡。外部地址那一列在 ESTABLISHED 状态下特别有用。你能看到本机正在和哪个远端 IP 的哪个端口通信。比如你怀疑服务器被人连了外部地址那一排排陌生的 IP 就能说明问题。最后一列 PID 的用法我前面提到了但在 Windows 上有个小坑如果是系统服务或内核进程占用的端口PID 往往是 4对应的是 System 进程。这种情况 taskkill 是杀不掉的得换个思路后面会专门说。2. 参数不只是记住含义每个字母背后解决什么问题很多教程喜欢把 netstat 的参数列表甩出来让人背背完还是不知道怎么用。我的建议是换个角度不用管参数叫什么先想清楚你此刻要排查什么问题再看用什么参数组合。2.1 从排查目标反推参数组合如果你要确认某个服务有没有正常启动核心是看监听端口用netstat -an过滤LISTENING状态就行。Windows 下可以这样netstat -an | findstr LISTENINGLinux 下更直接加个-l只看监听端口netstat -tlnp-t表示只看 TCP-l表示只看监听中的-n是数字显示-p在 Linux 下显示进程名和 PID。这一串组合在 Linux 上的使用频率极高可以说和 Windows 的-ano地位相当。如果你想看这台机器当前的实时连接状态分布用-an加统计命令。Windows 上可以用 findstr 加 find /c 来数数量Linux 上可以配 sort 和 uniqnetstat -ant | awk {print $6} | sort | uniq -c | sort -n这个命令可以列出 TIME_WAIT、ESTABLISHED、CLOSE_WAIT 等状态各有多少个是分析连接健康度最重要的一个手段。2.2 Windows 与 Linux 参数差异对照很多从 Windows 转 Linux 或者反过来的人最痛苦的就是参数不通用。-o在 Windows 下是显示 PID但在 Linux 下根本没这个参数Linux 下显示进程用的是-p。强烈建议收藏下面这个对照表排查目的Windows 常用组合Linux 常用组合查看全部连接netstat -annetstat -ant只看监听端口netstat -an | findstr LISTENINGnetstat -tlnp查看进程信息netstat -anonetstat -tlnp-p 显示进程查看路由表netstat -rnetstat -rn查看接口收发统计netstat -enetstat -i查看协议统计netstat -snetstat -s指定 IP 过滤netstat -an | findstr 192.168.1.10netstat -ant | grep 192.168.1.10这里单独说说-e和-s这两个相对冷门但很实用的参数。-e显示的是以太网接口的收发统计包括单播包、非单播包、丢弃包、错误包等。当你的网络出现能通但很慢的情况时看一眼 Errors 和 Discards 的数值是不是在持续增长能快速判断是不是网卡、网线或者驱动层面出了问题。-s显示的是各协议的统计信息TCP、UDP、ICMP 各有一大串计数。重点关注 TCP 部分的连接重置次数和 SYN 重传次数。如果重置次数异常多往往说明对端在拒绝连接或者半开连接清理不及时SYN 重传次数多说明握手包一直在丢失网络链路可能有丢包。值得一提的是Windows 下的-e和-s用了之后会显示 Interface Statistics 和 IPv4 Statistics 两组数据里面包含的 Segments Received/Segments Sent 和 Connection Failures 等计数长期监控对判断网络稳定性非常有参考价值。3. TCP 连接状态解码从状态机看懂连接的一生如果只看 IP 和端口netstat 还只是个查户口的工具。真正让它成为排障神器的是那一列 Status 状态值。TCP 是个有状态协议一个连接从建立到断开要经历好几种状态每个状态都对应着连接生命周期里的一个阶段。3.1 从握手到挥手的连接状态流转一个完整的 TCP 连接是这样流转的服务端先进入LISTENING状态监听某个端口客户端发起连接后先发出 SYN 包进入SYN_SENT服务端收到后进入SYN_RECEIVED回应 SYNACK客户端收到再回 ACK双方都进入ESTABLISHED连接建好。断开连接的时候主动关闭的一方先发 FIN 包进入FIN_WAIT_1收到对方 ACK 后进入FIN_WAIT_2对方发 FIN 后本机进入TIME_WAIT等 2MSL两倍最大报文生存时间后彻底关闭。被动关闭的一方收到 FIN 后进入CLOSE_WAIT此时如果应用层调用了 close就发 FIN 出去进入LAST_ACK收到对方最后的 ACK 才算关完。用文字画一条简易的流向图服务端LISTENING → SYN_RECEIVED → ESTABLISHED → CLOSE_WAIT → LAST_ACK → 关闭 客户端SYN_SENT → ESTABLISHED → FIN_WAIT_1 → FIN_WAIT_2 → TIME_WAIT → 关闭netstat 里看到的状态就是这条链路上的每一个信标。知道当前卡在哪个状态就能倒推出是哪一步出了问题。3.2 高频状态逐个拆解排查思路ESTABLISHED是理想状态表示连接健康。如果一台机器上有大量 ESTABLISHED 连接先看外部地址是哪些判断是正常业务流量还是异常扫描。SYN_SENT状态出现在客户端视角。如果你发现一个连接长时间停在 SYN_SENT说明 SYN 包发出去了但对端一直没有回应。这时候从本机 ping 一下对端 IP如果 ping 不通大概率是网络链路不通如果 ping 得通但 TCP 连不上十有八九是对端防火墙把端口给挡了。我在实际排查中遇到最多的情况就是云服务器安全组忘记放行端口现象就是 SYN_SENT 卡死。SYN_RECEIVED出现在服务端视角是收到了 SYN 但握手没完成的中间状态。如果短时间内出现大量 SYN_RECEIVED通常是半连接攻击或扫描行为。但也要排除一种正常情况客户端确实在大量发起短连接只是握手还没完成。这时候配合netstat -s看 SYN 重传计数就能区分是恶意行为还是正常业务波峰。TIME_WAIT是主动关闭方在连接结束后必须等待的 2MSL 时间窗口。很多人一看到 TIME_WAIT 数量多就紧张其实这是正常现象。只要你的服务是主动关闭连接的一方TIME_WAIT 是必经状态它的存在是为了保证最后一个 ACK 如果丢了能重发同时也防止旧连接的延迟报文段混入新连接。只有数量大到把端口资源耗尽时才需要做调优。CLOSE_WAIT是我最想让新人都记住的状态因为它几乎是最能反映应用代码质量的一个指标。它的含义是对端已经发起了关闭你的内核已经回复了 ACK但你的应用程序一直没有调用 close 去关闭这个 socket。通俗地说连接的另一半已经走了你这一半还攥着不放。如果 netstat 里出现大量 CLOSE_WAIT基本可以断定是应用层代码有 bug最常见的原因是读取完响应数据后没有关闭流或者没有释放连接。3.3 关于 TIME_WAIT 和 CLOSE_WAIT 的两个经典误判TIME_WAIT 和 CLOSE_WAIT 是最容易被搞混的两个状态这里放一起对比着说。TIME_WAIT 出现在主动关闭方数量多不等于故障。真正需要关注的是它有没有导致端口被占满。Windows 上可以用刚才的netstat -an | findstr TIME_WAIT加 find /c 统计数量如果数量接近几万甚至更多且新连接出现Address already in use的报错才需要去调整动态端口范围或开启 TIME_WAIT 重用Linux 下。CLOSE_WAIT 出现在被动关闭方数量只要持续增长几乎可以判定是代码问题。它不会像 TIME_WAIT 那样自己消失只会越堆越多最终把连接数耗尽服务表现为假死端口还在监听但新请求处理不动。遇到这种情况先netstat -ano | findstr CLOSE_WAIT统计数量再用netstat -ano | findstr CLOSE_WAIT配合按 PID 分组看是哪个进程然后去代码里找没关的 socket。说白了TIME_WAIT 是正常的善后工作CLOSE_WAIT 是没人来善后。4. 实战排查三个高频故障场景的完整处置链路参数讲得再多不如一场实战排查有说服力。这里分享三个我在工作中真实遇到过的场景每个都完整走一遍排查链路。4.1 案例一Windows 下 System 进程PID 4占用端口怎么办某次部署一个新的 Web 服务端口用的 8080启动时直接报错。用netstat -ano | findstr :8080一查好家伙PID 是 4。再tasklist | findstr 4显示的是 System 进程。普通进程可以用 taskkill 杀掉但这个 PID 4 是系统进程提示拒绝访问。后来排查下来是 Windows 的 HTTP.sys 服务把这个端口给保留了。Windows 上有不少系统组件比如 IIS、Windows 远程管理、甚至 Hyper-V会通过 HTTP.sys 监听特定端口范围。还有一个更隐蔽的情况Windows 在每次系统启动后会从动态端口范围里随机排除一段端口如果你的服务正好用到了这段同样会被提示端口被占用但 netstat 里根本查不到占用进程。遇到这种情况先执行netsh interface ipv4 show excludedportrange protocoltcp输出会列出系统保留的端口段。如果你的端口落在这些范围内说明它被 Windows 动态排除了要么换一个不在范围内的端口要么用netsh int ipv4 add excludedportrange调整保留范围。如果是 HTTP.sys 导致的也可以通过netsh http show servicestate查看具体是哪个服务在监听。这个案例的教训是netstat能告诉你被占了但有时候占用的不是某个常规进程而是操作系统自身的机制。这时候别急着 kill先看看是不是系统保留端口。4.2 案例二CLOSE_WAIT 堆积导致接口假死有次负责的一个 Java 服务上线两周后突然开始频繁超时。进程还在端口也在监听但请求就是处理不了。我用netstat -ano | findstr :8080 | findstr CLOSE_WAIT | find /c CLOSE_WAIT统计了一下CLOSE_WAIT 的数量从几十个涨到两千多个而且还在持续涨。按 PID 聚合之后发现全是 Java 进程的连接。那个服务是用 HttpClient 调用第三方接口的代码里在读取响应流的时候偷懒没有关闭 InputStream。响应流不关闭底层 socket 就不会释放每次调用第三方接口就漏一个 CLOSE_WAIT流量一大就堆起来了。这种问题重启服务可以暂时缓解但根因不修过几天又会复现。正确的做法是临时重启让连接归零然后改代码关闭流或者使用带连接池的 HTTP 客户端让框架负责连接生命周期。修复上线后再用同一个命令观察CLOSE_WAIT 数量不再增长问题才算真正解决。4.3 案例三大量 SYN_RECEIVED 不等于被攻击某天客户反馈服务器网络卡顿远程登录都困难。我看了一眼 netstat输出刷新得极慢好不容易出来结果SYN_RECEIVED 状态一大堆。第一反应像是半连接攻击但冷静下来先做了一步验证执行netstat -s重点看 TCP 部分的重传统计。对比数据后发现虽然 SYN_RECEIVED 多但 SYN 重传次数并没有异常飙升。再查外部地址发现来源 IP 集中在几个内网网段。最后定位到问题是内网某台机器上有个脚本在并发扫端口做健康检查频率设得太高把服务器的半连接队列给打满了。调整检查脚本的并发和频率之后SYN_RECEIVED 立刻降了下来。这个案例想说明的是看到 SYN_RECEIVED 大量出现第一反应不该是被攻击了而是先判断这些连接是否正常业务行为。用 netstat 的-s统计配合外部地址来源分析大概率能分清是恶意还是误用。网络安全领域讲究证据链netstat 输出就是最好的第一手证据。5. netstat 的边界什么时候它不够用了netstat 很强大但它不是万能的。我在连接数动辄几千上万的服务器上踩过坑一条netstat -ant敲下去光标能转好几秒钟才出结果。这时候不是命令没执行而是它确实处理不过来了。5.1 netstat 慢在哪儿Linux 下 netstat 的实现方式是逐个读取/proc/net/tcp之类的伪文件系统。每一条连接对应文件里的几行记录内核把所有原始数据倒出来netstat 再逐行解析成人类能看懂的格式。连接数少的时候没什么感觉一旦系统里同时存在几万个 socket文件系统读取加字符串解析的开销就会变得非常明显。而 ss 命令走的是 netlink 接口直接和内核通信拿到的是一份结构化的连接快照不需要解析文本所以同样连接数下ss 的速度能比 netstat 快一个量级。在我的实际测试中一个约 3 万连接的系统netstat 耗时十几秒ss 基本是秒出。5.2 Linux 下换用 ssWindows 下换用什么Linux 环境我现在的习惯是直接用 ss。常用的几个组合ss -tlnp # 查看监听的 TCP 端口和进程 ss -ant # 查看所有 TCP 连接的数字信息 ss -s # 连接统计总览 ss -ant state established # 只看 ESTABLISHED 状态的连接ss 的输出格式和 netstat 风格接近有过 netstat 基础的人切换成本极低。它还能按状态过滤比如ss -ant state time-wait直接列出所有 TIME_WAIT 连接不用再配合 grep 和 findstr 去处理了。Windows 上 netstat 依然是首选因为 Windows 没有 /proc 文件系统的性能包袱连接数一般也不会达到 Linux 那种恐怖量级。不过在 PowerShell 里还有一个更现代的替代Get-NetTCPConnection。它的优势是输出对象化的连接信息能直接用管道按状态、端口、进程 ID 做结构化过滤。比如查看 8080 端口上的监听进程Get-NetTCPConnection -LocalPort 8080 -State Listen | Select LocalAddress, LocalPort, OwningProcessOwningProcess拿到之后配合Get-Process -Id就能看到进程名。不过说实话日常快速排查我还是习惯直接敲 netstat毕竟命令短肌肉记忆已经形成了。5.3 会 netstat的边界在哪最后说点实在的。netstat 是网络排查的入门基本功这个地位不会变。甚至在很多精简容器镜像里系统工程师专门保留了 netstat 而不装其他网络工具因为它体积小、依赖少、老系统上一定有。学会 netstat等于在任何一台机器上你都有了一个最基础的网络视角。但我建议你在掌握 netstat 的同时也把 ss、lsof、Get-NetTCPConnection 这些工具纳入工具箱。单纯能背出参数不代表会用真正会用是知道这个命令现在的瓶颈在哪、下一个命令该用什么。我见过不少人卡在一个问题里很久就是因为只会反复敲同一条命令换个工具思路就打开了。比如lsof -i:8080在 Linux 上可以直接列出占用端口的进程名和 PID比netstat -tlnp | grep 8080更直观。查网络连接对应的进程名时lsof 也比 netstat 少一步反查。不过 lsof 的输出格式更偏文件描述符视角想快速看全量连接数据还是 ss 更顺手。最后再分享一个我自己的习惯每次部署完成先手动执行一遍netstat -an看看监听状态是否符合预期然后在巡检脚本里把netstat -s的关键计数、netstat -e的错误包记录定期抓一份快照。出了问题翻出历史快照对比往往比临时抱佛脚更能找到异常拐点。这个习惯帮我解决过好几起网络没问题但服务卡顿的疑难杂症也推荐你用起来。
返回列表