一句话答案:Clash Verge 启动提示 “listen tcp 127.0.0.1:7890: bind: address already in use”,核心根因在于后台残留的旧版代理(如 CFW、v2rayN)僵尸进程占用了 7890 混合端口、本地运维工具占用了 9090 控制器端口,或 Windows Hyper-V 动态保留端口段恰好覆盖了该端口。通过 netstat 查找 PID 强杀进程,或在设置中将混合端口直接修改为 7897/17890,即可 100% 极速自愈。
本文要点
- 核心要点:TCP/IP 协议规范要求同一 IP 地址上的同一端口在同一时间只能被单个进程独占绑定。
- 核心要点:7890 为混合代理端口 (Mixed Port),9090 为外部控制器 RESTful API 端口。
- 核心要点:Hyper-V 和 WSL2 重启后会随机随机保留数千个端口,将端口修改为高位段可永久避坑。
- 核心要点:修改端口后,终端 Git、Docker 以及浏览器 SwitchyOmega 插件必须同步更新端口号。
一、TCP/IP 套接字独占机制:操作系统为何拒绝端口绑定
在网络编程规范与 TCP/IP 体系中,操作系统使用 套接字(Socket) 作为网络通信的端点。一个网络监听套接字由一个四元组唯一标识:(协议, 本地 IP, 本地端口, 远程 IP, 远程端口)。
当 Clash Verge Rev 的底层核心(Mihomo)尝试提供代理入站服务时,它必须向操作系统内核发起 socket() 创建与 bind() 端口绑定系统调用:
+-----------------------------------------------------------------------------------+
| TCP 套接字独占绑定与端口冲突裁决流程图 |
+-----------------------------------------------------------------------------------+
│
[Mihomo 启动并请求 bind(AF_INET, SOCK_STREAM, 7890)]
│
▼
+---------------------------------------+
| Windows 内核套接字管理器 (Winsock) |
| 检查端口 7890 当前占用状态与绑定安全标志 |
+---------------------------------------+
│
┌───────────────────┴───────────────────┐
│ │
【端口已被其他进程独占绑定】 【端口处于绝对空闲状态】
│ │
▼ ▼
+-------------------------+ +-------------------------+
| 返回 WSAEADDRINUSE | | 返回 0 (绑定成功) |
| 内核抛出 Listen Error | | 进入 listen() 监听队列 |
+-------------------------+ +-------------------------+
│ │
▼ ▼
[Clash Verge 界面弹窗报警] [本地 7890 正常接管代理流量]
Windows 和大多数现代操作系统为了防止网络劫持,默认启用或强化了 SO_EXCLUSIVEADDRUSE 套接字安全选项:
- 如果一个进程已经成功在
127.0.0.1:7890或全局0.0.0.0:7890上建立了LISTEN状态,任何后续进程再次请求绑定完全相同的 IP 与端口时,内核会直接返回错误代码 WSAEADDRINUSE (10048)(即 Address already in use)。 - 这意味着操作系统从物理底层杜绝了“两个不同软件同时共享同一端口接收流量”的可能性。Mihomo 内核在捕获到该底层错误后无法继续拉起服务,只能被迫向 UI 抛出错误并终止。
二、常见端口冲突根因与全息排障矩阵
下表总结了 Clash Verge Rev 运行中最常见的端口冲突来源及其技术特征:
| 冲突端口号 | 默认核心功能 | 典型占用进程 / 冲突来源 | 严重级别 | 推荐解决路径 |
|---|---|---|---|---|
| 7890 | 混合代理端口 (Mixed Port) | 残留的 Clash for Windows、v2rayN、老旧代理服务 | 极高 (导致代理全盘瘫痪) | 强杀残留进程,或将端口改至 7897 / 17890 |
| 9090 | 外部控制器 RESTful API | Prometheus、Cockpit、本地 Go/Node.js 开发服务 | 高 (导致 UI 无法连通内核) | 在设置中修改外部控制端口至 9097 |
| 7897 | 现代 Verge 备选混合端口 | 其他开机自启的现代客户端 (如 Mihomo Party) | 高 | 避免同时开机运行多个代理客户端 |
| 1080 | SOCKS5 代理端口 | 旧版 Shadowsocks-libev、系统 SOCKS 服务 | 中 | 停用旧版工具,全部交由 Mihomo 托管 |
| 53 / 1053 | 本地 DNS 监听端口 | Windows Internet 连接共享 (ICS)、AdGuard Home | 极高 (导致 DNS 模块崩溃) | 关闭 Windows ICS 服务或修改 DNS 监听端口 |
| 动态段 | 随机高位端口 | Hyper-V / WSL2 动态保留端口黑洞 | 隐蔽 (netstat 查不到具体进程) | 调整 Windows 动态保留端口起始范围 |
三、实战排障:8 大极端边界冲突场景深度归因与自愈操作
场景 1:老版 Clash for Windows (CFW) 僵尸进程死锁 7890 端口
- 故障现象:双击 Clash Verge Rev 提示
listen tcp 127.0.0.1:7890: bind: address already in use。桌面上明明没有打开任何其他软件。 - 底层归因:用户此前电脑上安装了老版 CFW。在切换到 Verge 之前,用户虽然点击了 CFW 窗口的关闭按钮,但老版 CFW 默认仅仅是“最小化到托盘”;即使用户通过任务管理器强行关闭了主窗口,CFW 注册在系统后台的后台服务
clash-core-service依然作为独立进程在后台持续运行,死死咬住 7890 端口。 - 精准解决步骤:
- 打开任务管理器(
Ctrl + Shift + Esc),切换到“服务”选项卡。 - 寻找名为
Clash Core Service或clash-core-service的服务。 - 鼠标右键点击并选择“停止”;接着按下
Win + R输入services.msc,双击该服务将“启动类型”改为“禁用”。 - 重新启动 Clash Verge 即可秒级恢复。
- 打开任务管理器(
场景 2:9090 外部控制器端口被本地监控或开发服务占用
- 故障现象:客户端可以正常打开,但顶部或底部常态化弹窗提示
Failed to connect to external controller: 127.0.0.1:9090,且节点测速全部显示为 0。 - 底层归因:9090 是开源监控体系 Prometheus(普罗米修斯) 以及 Linux Web 管理后台 Cockpit 的默认服务端口。如果你是全栈工程师或在本地部署了 Docker 监控全家桶,Prometheus 会抢先霸占 9090 端口,导致 Mihomo 无法拉起 RESTful API 服务器,前端 UI 无法向核心发送控制指令。
- 精准解决步骤:
- 进入 Clash Verge 的“设置”页面。
- 找到“外部控制”或“控制器端口”设置项,将默认的
9090修改为一个完全冷门的高位端口(如9097或29090)。 - 点击“重启内核”,前端 UI 会立即以新端口与核心重新建立握手,故障瞬间消解。
场景 3:Windows 11 Hyper-V / WSL2 动态保留端口黑洞
- 故障现象:执行
netstat -ano | findstr 7890没有任何输出,任务管理器里没有任何软件在占用该端口,但 Clash Verge 启动依然报错“端口已被占用”! - 底层归因:这是 Windows 虚拟化架构(Hyper-V / WSL2)广为人知的“幽灵黑洞”。为了给内部容器分配网络,Windows 在每次开机时会从系统动态端口池中随机划出数个连续的端口范围。如果开机时分配算法恰好将
7890划入了保留范围,Winsock 内核就会对该端口实施无条件保留,导致普通应用根本无法绑定。 - 精准解决步骤:
- 在管理员 PowerShell 中运行命令验证:
netsh int ipv4 show excludedportrange tcp,查看 7890 是否落在某个被排除的端口区间内。 - 永久根治方案:通过注册表为 Windows 指定专用的动态端口起始范围,避开常用端口。在管理员终端执行:
netsh int ipv4 set dynamicport tcp start=49152 num=16384 - 或者直接在 Clash Verge 中将混合代理端口修改为高位端口
17890,彻底跳出 Hyper-V 的随机覆盖区。
- 在管理员 PowerShell 中运行命令验证:
场景 4:多代理客户端(v2rayN 与 Clash Verge)同时开机自启争抢
- 故障现象:电脑开机后有时 Clash Verge 能正常联网,有时却报错无法启动,具有明显的随机性。
- 底层归因:用户电脑的开机自启列表中同时勾选了 v2rayN 和 Clash Verge Rev。操作系统在启动应用时具有微秒级的时序不确定性。哪一个客户端先启动,哪一个就抢先霸占了 1080 / 7890 端口;后拉起的那一个必然会因端口已被占用而崩溃。
- 精准解决步骤:
- 统一客户端选型:建议日常主力只保留一个客户端开机自启。
- 打开任务管理器 ->“启动应用”,禁用多余代理客户端的开机自启开关。
场景 5:执行 taskkill 强杀进程提示“错误: 拒绝访问”
- 故障现象:在 CMD 或终端中执行
taskkill /F /PID 1234时,系统报错错误: 无法终止 PID 为 1234 的进程。原因: 拒绝访问。 - 底层归因:该占用进程是以最高管理员(Administrator)甚至系统服务(SYSTEM)身份启动的,而当前打开的命令行窗口仅仅具有受限的标准用户权限。
- 精准解决步骤:
按下
Win + S搜索“PowerShell”,在右侧点击“以管理员身份运行”。再次执行Stop-Process -Id 1234 -Force即可凭借最高特权强行回收套接字。
场景 6:修改端口为 7897 后外部开发工具网络报错全断
- 故障现象:用户在 Clash Verge 设置中将端口成功改为了 7897,软件不再报错了;但随后在终端中执行
git clone、npm install或使用 Postman 时,全部报错Proxy connection refused。 - 底层归因:开发者的全局环境变量(如
HTTP_PROXY、HTTPS_PROXY)或 Git 全局配置依然硬编码指向了旧的http://127.0.0.1:7890。由于 7890 已经没有服务在监听,外部工具的所有网络请求全部撞墙。 - 精准解决步骤:
- 更新 Git 代理配置:
git config --global http.proxy http://127.0.0.1:7897 git config --global https.proxy http://127.0.0.1:7897 - 检查环境变量:在系统属性中将
HTTP_PROXY对应的值同步修正为7897。
- 更新 Git 代理配置:
场景 7:局域网共享模式(Allow LAN)开启后外网设备连接失败
- 故障现象:开启了“允许局域网连接”,但在同局域网的手机上配置该电脑的 IP 和 7890 端口,手机依然无法上网,提示连接超时。
- 底层归因:Mihomo 内核虽然成功监听了
0.0.0.0:7890,但 Windows 防火墙(Windows Defender Firewall)的高级安全规则默认拦截了来自非本机 IP 的外部 TCP 入站连接。 - 精准解决步骤:
在管理员 PowerShell 中运行以下命令,为 Clash Verge 添加入站防火墙白名单:
New-NetFirewallRule -DisplayName "Clash Verge Mixed Port" -Direction Inbound -LocalPort 7890,7897 -Protocol TCP -Action Allow
场景 8:DNS 监听端口 53 冲突导致内核全盘闪退
- 故障现象:在配置中开启了本地 DNS 监听后,核心闪退报错
listen udp 127.0.0.1:53: bind: permission denied / address already in use。 - 底层归因:53 是标准的系统 DNS 端口。Windows 系统的“Internet 连接共享服务(SharedAccess)”默认霸占了本地 53 端口;在 Linux 系统中
systemd-resolved也会常驻监听 127.0.0.53:53。 - 精准解决步骤:
不要强求 Mihomo 监听 53 端口!在配置的
dns:模块中将listen:设置为非标准端口(如0.0.0.0:1053),或者依靠 TUN 模式进行透明重定向,即可完美绕开 53 端口冲突。
四、场景化决策选型卡片
合理规划本地开发环境与网络服务体系:
::: tip 💡 端口规划黄金准则
在复杂的工程生产力环境中,绝不要将所有网络服务堆叠在 7890 和 9090 这类大众通用端口上。建议资深开发者在首次配置 Clash Verge Rev 时,主动将混合代理端口自定义为高位端口(如 7897 或 17890),将外部控制器端口自定义为 9097。这能让你从物理上 100% 免疫未来所有潜在的第三方软件冲突与 Hyper-V 保留黑洞。
:::
::: warning ⚠️ 区分本地端口冲突与远端专线阻断
很多技术人员在遇到网络连接超时时,往往首先怀疑是本地端口被占用了;但当通过排查确认端口监听完全正常后,才发现是低质公共节点发生了大面积封锁、境外落地机房断流!
为了保障关键业务与远程生产力绝不中断,常备一套高质量的物理专线(IPLC / IEPL)服务是专业工程团队的标准实践:
佣金与商业合规披露声明:本站所收录或提及的部分网络服务包含推广导流链接;通过相关链接注册可能会为本站带来一定的运维佣金,但这绝不会对您的实际订购价格产生任何影响。本站始终坚守独立客观的技术评测底线。请使用者严格遵守中华人民共和国网络安全法律法规,文明合法使用网络资源。
五、自动化端口占用排查与一键强杀脚本
以下由 ClashNet 技术实验室精心编写的自动化排障脚本,支持毫秒级定位占用 7890/9090 的流氓进程并执行一键精准清理:
Windows 自动化端口排查与强杀脚本 (PowerShell)
# ==============================================================================
# ClashNet 官方出品:端口冲突排查与僵尸进程一键强杀工具 (PowerShell)
# 请使用管理员身份打开 PowerShell 运行
# ==============================================================================
Write-Host "==========================================================" -ForegroundColor Cyan
Write-Host " Clash Verge 端口占用分析与自动化一键清理工具" -ForegroundColor Cyan
Write-Host "==========================================================" -ForegroundColor Cyan
$targetPorts = @(7890, 7897, 9090, 1080)
foreach ($port in $targetPorts) {
Write-Host "`n[*] 正在扫描端口 [$port] 状态..." -ForegroundColor Yellow
$connections = Get-NetTCPConnection -LocalPort $port -State Listen -ErrorAction SilentlyContinue
if ($connections) {
foreach ($conn in $connections) {
$pidNum = $conn.OwningProcess
$proc = Get-Process -Id $pidNum -ErrorAction SilentlyContinue
$procName = if ($proc) { $proc.ProcessName } else { "未知系统进程" }
$procPath = if ($proc) { $proc.Path } else { "未知路径" }
Write-Host " [-] 警告:端口 [$port] 正在被监听!" -ForegroundColor Red
Write-Host " 进程 PID : $pidNum" -ForegroundColor Cyan
Write-Host " 进程名称 : $procName" -ForegroundColor Cyan
Write-Host " 可执行路径 : $procPath" -ForegroundColor Gray
# 提示是否强杀
$choice = Read-Host " -> 是否强杀该进程并释放端口 $port ? (y/n)"
if ($choice -eq 'y' -or $choice -eq 'Y') {
Stop-Process -Id $pidNum -Force -ErrorAction SilentlyContinue
Write-Host " [+] 已成功强制终止进程 PID: $pidNum,端口已释放!" -ForegroundColor Green
}
}
} else {
Write-Host " [+] 端口 [$port] 状态正常:完全空闲,无任何进程占用。" -ForegroundColor Green
}
}
Write-Host "`n[*] 正在查询 Windows Hyper-V 动态保留端口范围..." -ForegroundColor Yellow
$excluded = netsh int ipv4 show excludedportrange tcp | Out-String
if ($excluded -match "7890") {
Write-Host " [-] 严重提示:端口 7890 当前正处于 Hyper-V 排除保留列表中!建议将 Verge 端口修改为 7897 或 17890。" -ForegroundColor Red
} else {
Write-Host " [+] 7890 未被 Hyper-V 保留,环境安全。" -ForegroundColor Green
}
Write-Host "`n==========================================================" -ForegroundColor Cyan
Write-Host " 排查流程执行完毕!" -ForegroundColor Green
Write-Host "==========================================================" -ForegroundColor Cyan
macOS / Linux 终端端口排查与清理命令 (Bash)
#!/usr/bin/env bash
# ==============================================================================
# ClashNet 官方出品:macOS / Linux 端口占用排查与清理脚本
# ==============================================================================
PORTS=(7890 7897 9090)
for port in "${PORTS[@]}"; do
echo -e "\x1b[36m=== 检查端口: $port ===\x1b[0m"
PID=$(lsof -ti :$port)
if [ -n "$PID" ]; then
PROC=$(ps -p $PID -o comm=)
echo -e "\x1b[31m[-] 端口 $port 被进程 $PROC (PID: $PID) 占用!\x1b[0m"
read -p "是否立即终止该进程以释放端口?(y/n): " confirm
if [ "$confirm" = "y" ]; then
kill -9 $PID && echo -e "\x1b[32m[+] 已成功终止 PID: $PID\x1b[0m"
fi
else
echo -e "\x1b[32m[+] 端口 $port 处于空闲状态。\x1b[0m"
fi
done
六、长尾技术深度常见问答 (FAQ)
Q1:修改了 7890 混合端口后,以前配置的 Git 命令行和浏览器插件会失效吗?
会失效!如果此前你在终端执行过 git config --global http.proxy http://127.0.0.1:7890,或者在 Chrome 的 SwitchyOmega 插件中配置了 127.0.0.1:7890,一旦你将 Clash Verge 的端口修改为了 7897,那些外部程序向 7890 发起的请求都会被系统直接拒绝(Connection Refused)。你必须同步更新外部程序的代理端口配置。
Q2:为什么提示 9090 端口被占用?这个端口不是代理端口吧?
9090 是 Mihomo 内核的外部控制器(External Controller)API 端口,而不是传输代理数据的端口。前端图形界面(UI)需要通过访问 http://127.0.0.1:9090 来实时获取节点延迟、切换分流策略并拉取流量图表。在设置的“外部控制”中将其修改为 9097 或 19090 即可轻松解决冲突。
Q3:在 PowerShell 中使用 taskkill /F /PID 强杀进程提示“拒绝访问”怎么办?
这表明占用该端口的进程是以更高的系统级权限(如 NT AUTHORITY\SYSTEM)或 Windows 服务模式运行的,标准用户权限的终端无权终止它。必须以鼠标右键点击“终端”并选择“以管理员身份运行”,再次执行终止命令;或者进入 services.msc 找到对应的系统服务手动停止。
Q4:什么是 Windows 的 Hyper-V / WSL2 动态保留端口黑洞?
Windows 开启 Hyper-V、WSL2 或沙盒后,系统在开机阶段会为容器网络驱动动态预留多个连续的端口段(通常为 1000 个端口一段)。由于这些端口是内核网络栈预先锁定的,netstat 甚至查不到任何占用进程,但普通程序调用 bind() 时系统直接报错。遇到这种情况,通过 netsh int ipv4 show excludedportrange tcp 可以查看被排除的端口范围。
Q5:为什么我已经把老版 Clash for Windows 关掉了,任务管理器里也没有,还是提示占用?
因为老版 CFW 的“系统服务(Clash Core Service)”并没有随主界面退出而停止!老版 CFW 会在后台常驻一个名为 clash-core-service 的 Windows 系统服务,这个服务依然在静默监听 7890 端口。按下 Win + R 输入 services.msc,找到该服务右键点击“停止”并将其启动类型设置为“禁用”。
Q6:Clash Verge 支持将端口绑定在 0.0.0.0 吗?有安全风险吗?
当开启“允许局域网连接(Allow LAN)”时,Mihomo 会自动将监听地址从 127.0.0.1 扩展至 0.0.0.0:7890。这允许手机、电视等同局域网设备共享代理;但在公共 Wi-Fi(如咖啡厅、机场公共网络)环境下,任何人都能探测到你的开放端口并白嫖甚至扫描你的本地服务。在公共网络下建议关闭 Allow LAN,或设置高强度认证密码(Secret)。
Q7:在 macOS / Linux 下,端口被占用怎么查?
在终端中直接运行命令 lsof -i :7890 或 sudo netstat -tulpn | grep 7890。命令会清晰打印出占用进程的名称(COMMAND)和进程 ID(PID)。随后执行 kill -9 <PID> 即可瞬间清理。
Q8:为什么有时候把端口改成了 1080,提示由于权限无法启动?
在 Linux 和 macOS 系统中,小于 1024 的端口属于“特权端口(Privileged Ports)”,必须具备 root 超级用户权限才能绑定。虽然 1080 大于 1024,但 1080 是标准的 SOCKS 历史保留端口,极易与系统已有的 socks 守护进程冲突。建议日常使用 7890、7897 或 10000 以上的高位非特权端口。