Windows Server如何查看端口监听状态?命令行与图形工具教程

新上线的站点起不来,日志里一句“Address already in use”;客户说访问不了你的服务,你却在服务器上找不到任何异常;安全同事发来一份漏洞清单,要求你确认这台机器到底开哪些端口对外。这三个场景的共同起点,都是同一件事:搞清楚 Windows Server 当前的端口监听状态。

Linux 上有 ss -lntp,Windows 上同样有完整的工具链。本文从最经典的 netstat -ano 讲到现代 PowerShell 的 Get-NetTCPConnection,再补充资源监视器、TCPView、PortQry 等图形与第三方工具,并给出 TCP 状态判读标准和“端口被占”的实战处理流程。

一、先建立概念:三种端口视图的区别

很多人一说“看端口”就敲 netstat -an,然后被几千行输出淹没。其实你需要先明确自己要回答的是哪个问题:

要回答的问题该看什么对应状态 / 命令要点
本机开了哪些服务端口对外监听(Listening)套接字State = Listen;netstat -ano | findstr LISTENING
现在谁在连我、连了多少已建立(Established)连接State = Established,按远端 IP 聚合统计
某个端口为什么起不来占用进程 PID / 排除端口范围-o 参数、netsh int ipv4 show excludedportrange
连接是不是快耗尽了TIME_WAIT / CLOSE_WAIT 数量按状态分组计数,判断阈值

TCP 状态速查,这几条最常用来判断故障:

  • LISTENING:本地正在监听,等待连接。这是“服务有没有起来”的直接证据。
  • ESTABLISHED:连接已建立,正在传输数据。
  • TIME_WAIT:本端主动关闭后进入的等待状态,默认约 240 秒(2×MSL,注册表 TcpTimedWaitDelay 可调,范围 30–300 秒,不同版本默认值略有差异)。大量堆积通常是短连接并发过高。
  • CLOSE_WAIT:对端已关闭,本端还没关。这个状态持续大量出现基本是应用程序 Bug——代码里 socket 忘了 close,属于文件描述符/句柄泄漏,必须改程序。
  • SYN_RECEIVED:半连接积压,短时间内大量出现要怀疑 SYN Flood 或后端处理不过来。

二、CMD 经典方案:netstat -ano

netstat 从 Windows NT 时代就在,兼容性最好,Server 2003 到 2025 都能跑,是排障第一反应命令。参数含义:-a 显示所有连接与监听端口,-n 以数字形式显示地址和端口(不加会做 DNS 反解,巨慢),-o 显示占用进程的 PID,-b 显示可执行程序名(需要管理员权限),-p tcp 只看 TCP。

REM 查看所有监听端口 + 对应 PID(最常用)
netstat -ano | findstr LISTENING

REM 精确查某个端口,注意冒号,避免匹配到 PID
netstat -ano | findstr ":80 "
netstat -ano | findstr ":443"

REM 按状态筛选已建立连接
netstat -ano -p tcp | findstr ESTABLISHED

REM 显示占用端口的可执行程序(必须管理员 CMD)
netstat -anob

REM 统计各状态连接数(需要按状态计数时用 find /c)
netstat -ano -p tcp | find /c "ESTABLISHED"
netstat -ano -p tcp | find /c "TIME_WAIT"

拿到 PID 之后反查进程:

REM 方式一:tasklist
tasklist /fi "PID eq 4820"

REM 方式二:强行结束(确认业务影响后再操作)
taskkill /PID 4820 /F

REM 方式三:wmic(老系统兼容)
wmic process where processid=4820 get name,executablepath,commandline

一个实用技巧:把监听端口导出成文件做基线对比。服务器上线后跑一次 netstat -ano > C:\baseline_ports.txt,日后排查时用 fc 对比差异,能立刻发现“多出来”的可疑监听。

三、PowerShell 现代方案:Get-NetTCPConnection

Server 2012 / PowerShell 3.0 起提供了 Get-NetTCPConnection(模块 NetTCPIP),输出是对象而不是文本,可以直接筛选、排序、管道传递,比 netstat 强太多。强烈建议在 PowerShell 环境里优先用它。

# 列出所有监听端口(SNAT 绑定的除外),按端口排序
Get-NetTCPConnection -State Listen | Sort-Object LocalPort |
  Select-Object LocalAddress, LocalPort, State, OwningProcess

# 一步到位:把 PID 换成进程名(最常用的一段)
Get-NetTCPConnection -State Listen |
  Select-Object LocalAddress, LocalPort,
    @{n='ProcessName';e={(Get-Process -Id $_.OwningProcess -ErrorAction SilentlyContinue).ProcessName}},
    @{n='Path';e={(Get-Process -Id $_.OwningProcess -ErrorAction SilentlyContinue).Path}} |
  Sort-Object LocalPort | Format-Table -AutoSize

# 精确查某端口
Get-NetTCPConnection -LocalPort 3389 -ErrorAction SilentlyContinue

# 查到某个远端的所有连接(判断客户端是否连上来了)
Get-NetTCPConnection -RemoteAddress 203.0.113.25

# 按状态统计连接数,判断 TIME_WAIT 是否堆积
Get-NetTCPConnection | Group-Object State | Sort-Object Count -Descending |
  Select-Object Count, Name
# UDP 端点用另一条 cmdlet(DHCP、DNS、SNMP 类服务常见)
Get-NetUDPEndpoint | Select-Object LocalAddress, LocalPort, OwningProcess

# 查看某进程占用的全部端口(先查 PID)
$p = (Get-Process -Name nginx).Id
Get-NetTCPConnection -OwningProcess $p -ErrorAction SilentlyContinue

# 查看动态端口(临时端口)范围
Get-NetTCPSetting | Select-Object SettingName, DynamicPortRangeStartPort, DynamicPortRangeNumberOfPorts

一个高频需求:统计“哪个远端 IP 连接最多”,用于识别异常来源或 DDoS。一行管道就够:

Get-NetTCPConnection -State Established |
  Where-Object { $_.RemoteAddress -notmatch '^(127\.|::1|fe80:)' } |
  Group-Object RemoteAddress | Sort-Object Count -Descending |
  Select-Object -First 10 Count, Name

四、端口被占用却查不到进程?检查排除端口范围

这是 Windows 特有、且极其容易让人抓狂的坑:明明 netstat 显示端口空闲,程序一 bind 就报 10013 / 10048 错误。原因通常是该端口落在了系统保留(excluded)端口范围内——Hyper-V、WSL、Docker、Windows NAT 会在启动时向系统申请一段端口保留,这些端口不在 netstat 里显示,但别人也用不了。

REM 查看 IPv4 TCP 排除端口范围(管理员权限)
netsh int ipv4 show excludedportrange protocol=tcp

REM 查看 IPv6 / UDP
netsh int ipv6 show excludedportrange protocol=tcp
netsh int ipv4 show excludedportrange protocol=udp

REM 查看动态端口范围(Server 2008 起默认 49152-65535,共 16384 个)
netsh int ipv4 show dynamicport tcp

REM 查看具体保留项(Docker / Hyper-V 常见)
netsh int ipv4 show excludedportrange protocol=tcp
netsh int ipv4 show dynamicport udp

处理办法有三种:一是把应用端口改到保留范围之外;二是重启相关服务(如 Restart-Service hns 或停用 Hyper-V 后重启)让保留释放;三是用 netsh int ipv4 add excludedportrange 主动把自己要用的端口永久保留下来,避免被系统临时分配走。

另一个常见场景:80/443 被 HTTP.SYS(内核态 HTTP 驱动)占用,IIS、SQL Server Reporting Services、WinRM、Web 部署服务都会用到它。此时 netstat 里的 PID 往往是 4(System),需要用专门的命令看:

REM 查看 HTTP.SYS 的 URL 保留与监听队列
netsh http show servicestate view=requestq
netsh http show urlacl
netsh http show iplisten

五、图形化工具:不敲命令也能看清楚

并不是所有场合都适合命令行。给领导演示、给不懂技术的同事定位、或者在客户机上临时排查时,图形工具更直观。

工具打开方式适用场景备注
资源监视器resmon.exe → “网络” 选项卡 → “侦听端口”系统自带,直观显示端口、进程、防火墙状态无需联网安装,首选
任务管理器Ctrl+Shift+Esc → 性能 → 打开资源监视器顺路查看时功能较弱
TCPViewSysinternals 套件,官网下载实时刷新、颜色标示状态变化、可右键杀进程最推荐,绿色单文件
PortQry / PortQryUIMicrosoft 下载中心从客户端测试对端端口是否开放输出 listening / filtered / not listening
Windows 防火墙日志%systemroot%\System32\LogFiles\Firewall\pfirewall.log确认是不是被防火墙丢包需先启用日志记录

如果不想装任何东西,用 PowerShell 自带的 Test-NetConnection 从客户端探测对端端口,是判断是否被防火墙拦的最快手段:

# 从客户端探测服务端端口(替代 telnet,Windows 默认不装 telnet 客户端)
Test-NetConnection 192.168.10.20 -Port 8080

# 只要布尔结果,方便写脚本
(Test-NetConnection 192.168.10.20 -Port 8080 -WarningAction SilentlyContinue).TcpTestSucceeded

# 批量探测多个端口
3306,3389,8080,443 | ForEach-Object {
  $r = Test-NetConnection 192.168.10.20 -Port $_ -WarningAction SilentlyContinue
  [PSCustomObject]@{ Port=$_; Open=$r.TcpTestSucceeded }
}

命令输出解读:TcpTestSucceeded = True 说明链路和监听都正常;False 且 Ping 通,说明监听没起或被防火墙拦;Ping 不通则先看网络层。

六、标准操作清单:从“端口不通”到定位根因

  1. 确认服务监听:服务端执行 Get-NetTCPConnection -LocalPort <端口> -State Listen,无输出说明服务没起来或监听地址不对。
  2. 核对监听地址:LocalAddress 是 0.0.0.0 表示所有网卡都听;若是 127.0.0.1,则外部永远访问不到,需要改应用绑定配置。
  3. 反查进程:用 OwningProcess 拿 PID,再用 Get-Process -Id 或 tasklist /fi 确认是哪个程序。
  4. 服务端本地自测:在服务本机执行 Test-NetConnection 127.0.0.1 -Port <端口>,排除应用自身问题。
  5. 跨机测试:从客户端测对端 IP 的端口,判断是网络/防火墙问题还是应用问题。
  6. 查防火墙:Get-NetFirewallRule 或直接看 netsh advfirewall firewall show rule name=all 中对应端口的入站规则。
  7. 查排除端口范围:bind 失败但端口空闲时,执行 netsh int ipv4 show excludedportrange protocol=tcp。
  8. 留基线:把正常状态下的监听列表导出存档,作为日后对比的依据。

小结与避坑建议

Windows Server 查看端口监听状态,日常记住两条命令就够用:CMD 下 netstat -ano | findstr LISTENING,PowerShell 下 Get-NetTCPConnection -State Listen 配合 Get-Process 把 PID 翻译成进程名。需要实时观察就用 TCPView,需要从外部探测就用 Test-NetConnection 或 PortQry。

几条实践建议:

  • 永远加 -n。不加 -n 的 netstat 会对每个远端 IP 做反向 DNS 解析,在连接数多时可能卡住几十秒。
  • 把端口基线做成日巡检项。一台服务器对外开的端口应该是固定的,多出一个监听就值得追查,这是发现后门和挖矿程序最朴素也最有效的手段。
  • CLOSE_WAIT 堆积不要靠重启解决。重启只能临时清空,根因是应用程序没有关闭 socket,必须从代码或组件版本入手。
  • TIME_WAIT 多不一定是问题。短连接服务(HTTP 轮询、API 调用)天生会产生大量 TIME_WAIT,只有当它接近动态端口上限(默认 16384 个)并伴随新建连接失败时才需要处理。
  • 警惕 PID = 4 的占用。它代表 System 进程,真正的占用者往往是内核态的 HTTP.SYS 或其他驱动,要用 netsh http show servicestate 才能看清。
  • 生产环境不要凭 PID 直接 kill。先用 Get-Process -Id 确认路径和命令行,误杀数据库或服务进程代价太大。

把这套方法整理成脚本放进运维工具箱,下次遇到“端口不通”,你就能在两分钟内给出确定答案,而不是靠重启碰运气。