记一次Windows端口占用问题排查

简介: netstat命令排查不出的Windows端口占用问题的解决方案,附快速排查脚本

换了一家公司,新公司的网络环境只支持Windows,于是从Mac切换到了Windows。由此遇到了很多很多的问题,在此记录一些比较典型的问题。

问题记录

我要启动一个Docker容器,想要使用9595端口。使用的命令如下:

docker run -d ^
-p 9595:80 ^
--name doc-server ^
-v //d/docker_share/doc-server/helper:/usr/share/nginx/html/helper:ro ^
-v //d/docker_share/doc-server/config/nginx.conf:/etc/nginx/nginx.conf:ro ^
nginx:1.29.0

运行得到了异常结果:

docker: Error response from daemon: Ports are not available: exposing port TCP 0.0.0.0:9595 -> 0.0.0.0:0: listen tcp 0.0.0.0:9595: bind: An attempt was made to access a socket in a way forbidden by its access permissions.

从字面上来看,就是绑定9595接口失败了。因为9595端口较高,一般不会是系统保留,所以我们排查一下是不是其他程序占用了该端口:

netstat -ano | findstr "9595"

排查结果:
端口占用问题排查-netstat排查结果-1.png

找不到占用了该端口的程序。

既然不是应用程序占用,会不会是系统把端口保留了?使用命令排查一下:

netsh interface ipv4 show excludedportrange protocol=tcp

排查结果如下:
端口占用问题排查-netsh排查结果-1.png

可以发现,9595端口确实被系统占用了。

查询资料了解到这种情况一般是由于:
Windows 10/11 会为系统服务(Hyper-V、RPC、某些安全软件、WSL2、VPN、Edge 浏览器的调试端口等)预留一批端口,以防被其他程序抢占。

造成 9595 这种高位端口被保留的常见原因:

  • Hyper-V / WSL2:Docker Desktop 会依赖它,启动时会预留一批高端口。
  • Windows 服务(WinRM、Net.TCP Port Sharing Service 等):这些可能预留固定区间。
  • VPN 或代理软件:有些会锁定一批端口用作隧道连接。
  • 曾经被用作 RPC 端口范围:RPC Endpoint Mapper 会随机分配高位端口给服务,系统会提前标记。

在这种情况下,如果一定要使用这个端口,可以使用以下的命令:

netsh int ipv4 delete excludedportrange protocol=tcp startport=9595 numberofports=1

端口排查脚本的运行

基于上面的各种步骤,我写了一个脚本以方便排查过程。

# 让用户输入端口号
$Port = Read-Host "请输入要检查的端口号"

Write-Host "正在检查端口 $Port ..." -ForegroundColor Cyan

# 1. 检查端口是否在保留范围内
$excluded = netsh interface ipv4 show excludedportrange protocol=tcp |
    ForEach-Object {
    $_.Trim() } |
    Where-Object {
    $_ -match '^\d+' } |
    ForEach-Object {
   
        $parts = $_ -split '\s+'
        [PSCustomObject]@{
   
            StartPort = [int]$parts[0]
            EndPort   = [int]$parts[1]
        }
    }

$inRange = $excluded | Where-Object {
    $Port -ge $_.StartPort -and $Port -le $_.EndPort }

if ($inRange) {
   
    Write-Host "! 端口 $Port 位于系统保留区间: $($inRange.StartPort)-$($inRange.EndPort)" -ForegroundColor Yellow
} else {
   
    Write-Host "- 端口 $Port 不在保留区间" -ForegroundColor Green
}

# 2. 检查是否有进程占用
$connection = Get-NetTCPConnection -LocalPort $Port -ErrorAction SilentlyContinue
if ($connection) {
   
    $pid = $connection.OwningProcess
    $proc = Get-Process -Id $pid -ErrorAction SilentlyContinue
    Write-Host "! 端口 $Port 被进程占用:" -ForegroundColor Red
    Write-Host ("   进程名: {0}" -f $proc.ProcessName)
    Write-Host ("   PID: {0}" -f $pid)
} else {
   
    Write-Host "- 端口 $Port 当前没有进程监听" -ForegroundColor Green
}

# 3. 如果是保留状态,提示可能来源
if ($inRange -and -not $connection) {
   
    Write-Host "`n可能的保留来源:" -ForegroundColor Cyan
    Write-Host " - Hyper-V / WSL2(Docker Desktop 依赖它)"
    Write-Host " - VPN 或代理软件"
    Write-Host " - Windows RPC / WinRM 服务"
    Write-Host " - 某些杀毒软件或公司策略"
}

可以将它保存成一个.ps1格式的脚本文件,这里以port_check.ps1为例。注意:由于Windows的PowerShell编码问题,如果使用Windows自带的版本(未自行升级),编码需要保存为GBK。要运行它,有以下几种方法:

使用powershell窗口运行

因为要使用管理员权限,所以对着脚本使用右键菜单中的"使用PowerShell运行"是无效的,使用时会直接闪退且没有任何错误提示。我们只能手动在开始菜单中搜索PowerShell,使用管理员身份运行。
端口排查脚本-使用管理员身份打开powershell.png

在窗口中使用以下命令:

Set-ExecutionPolicy -Scope Process -ExecutionPolicy Bypass
D:\tmp\port-check-scripts\port_check.ps1

这其中,Set-ExecutionPolicy -Scope Process -ExecutionPolicy Bypass用于对PowerShell窗口进行提权,D:\tmp\port-check-scripts\port_check.ps1是脚本的路径,按照实际情况进行替换。

使用外部CMD窗口运行

因为右键菜单中不包含以管理员身份运行PowerShell的命令,因此我又写了一个cmd脚本来唤起管理员身份的PowerShell窗口以运行这个文件。

@echo off
:: 检查是否是管理员权限
net session >nul 2>&1
if %errorlevel% neq 0 (
    echo 正在以管理员权限重新启动...
    powershell -Command "Start-Process cmd -ArgumentList '/c \"%~f0\"' -Verb RunAs"
    exit /b
)

:: 获取当前脚本所在目录(自动加引号防止空格问题)
set "CurrentDir=%~dp0"

:: 检查 check-port.ps1 是否存在
if not exist "%CurrentDir%port_check.ps1" (
    echo 找不到 "%CurrentDir%port_check.ps1"
    pause
    exit /b
)

:: 运行 PowerShell 脚本
powershell -NoExit -ExecutionPolicy Bypass -File "%CurrentDir%port_check.ps1"

将其保存为.cmd文件,如run.cmd,与刚刚的port_check.ps1放在同一目录下,双击运行就行了。

运行效果如图:

端口排查脚本-脚本运行效果1.png

目录
相关文章
Error: listen EACCES: permission denied 0.0.0.0:80
Error: listen EACCES: permission denied 0.0.0.0:80
|
SQL XML 关系型数据库
Mybatis-Plus通过SQL注入器实现真正的批量插入
Mybatis-Plus通过SQL注入器实现真正的批量插入
7654 0
Mybatis-Plus通过SQL注入器实现真正的批量插入
|
6月前
|
SQL Java 数据库连接
Mybatis的批处理工具:MybatisBatchUtils功能全解
总而言之,MybatisBatchUtils 是 Mybatis 的一款强大工具,可以显著提高批量数据处理的效率,并确保事务的安全性。通过简化 API 的设计,使得开发者能够易于上手并利用 Mybatis 进行高效的数据库操作。正确使用 MybatisBatchUtils,必然能够在大数据量的场景下,给你的应用性能带来质的飞跃。
485 0
Yum工具详解(二)-----Yum配置阿里源
Yum工具详解(二)-----Yum配置阿里源
5811 1
|
8月前
|
编解码 Java 计算机视觉
探索 JavaCV:开启计算机视觉与多媒体处理新世界
JavaCV 是基于 OpenCV 和 FFmpeg 的 Java 接口库,助力开发者实现视频处理、图像分析等功能。支持多种音视频格式编解码、GPU 加速及跨平台运行,适用于直播录制、摄像头捕获、美颜相机等场景,是多媒体开发的利器。
673 1
|
Docker Windows 容器
解决 windows:An attempt was made to access a socket in a way forbidden by its access permissions
解决 windows:An attempt was made to access a socket in a way forbidden by its access permissions
4207 2
解决 windows:An attempt was made to access a socket in a way forbidden by its access permissions
|
4月前
|
存储 搜索推荐 数据库
🚀 RAGFlow Docker 部署全流程教程
RAGFlow是开源的下一代RAG系统,融合向量数据库与大模型,支持全文检索、插件化引擎切换,适用于企业知识库、智能客服等场景。支持Docker一键部署,提供轻量与完整版本,助力高效搭建私有化AI问答平台。
3242 8