#v2rayA #Windows #nssm #服务器运维

milin_desktop 上的 v2rayA 突然用不了,Web UI 点"启动"就弹报错。排查发现既不是网络问题也不是后端挂了,而是上一次残留的 xray-core 进程变成孤儿、一直霸占入站端口,导致新 core 起不来。记录定位过程与用 nssm 事件钩子防复发的做法。


环境

  • 主机:milin_desktop(Windows 11,192.168.2.10

  • 安装:D:\Program Files (x86)\v2raya\,以 nssm 注册成服务 v2raya--lite --v2ray-bin ...\v2ray.exe

  • core:实为 xray-core 2.4.6

  • Web UI:http://192.168.2.10:2017

  • 日志:安装目录 v2raya-stdout.log / v2raya-stderr.log(nssm 重定向)

  • 配置/资产目录:C:\Users\milin\AppData\Roaming\v2rayA


一、症状与初判

Web UI 点"启动"弹报错,代理不可用。先看进程和服务——都在跑,说明后端没死:

1
2
Get-Process *v2ray* | Select Name,Id,Path
Get-Service *v2raya* | Select Name,Status,StartType # Running / Automatic

于是问题落在"点启动时 core 拉起失败"。翻日志找真因。


二、日志定位:端口已被占用

v2raya-stdout.log 末尾:

1
2
3
4
5
Failed to start: app/proxyman/inbound: failed to listen TCP on 20170 >
... listen tcp [::1]:20170: bind: Only one usage of each socket address
(protocol/network address/port) is normally permitted.
v2ray-core: exit status 0xffffffff
failed to start v2ray-core: unexpected exiting

Only one usage of each socket address 是 Windows 版的 EADDRINUSE。v2rayA 让新 core 在内部端口 20170/20171/20172 开入站监听,但端口被占了。日志还有一句自相矛盾的线索:

1
the core was not running the last time v2rayA exited

v2rayA 认为上次退出时 core 没在跑,可端口偏偏被 v2ray.exe 占着——典型的孤儿 core

查占端口的进程:

1
2
3
$c = Get-NetTCPConnection -LocalPort (20170..20172) -State Listen
$c | Select LocalAddress,LocalPort,OwningProcess
$c.OwningProcess | Sort -Unique | % { Get-Process -Id $_ | Select Id,Name,Path,StartTime }

结果:端口全被 v2ray.exe(PID 23388,启动于当天更早、比现役 v2raya 服务还老)占据——它是上一轮 v2rayA 实例遗留、没被回收的子进程。


三、修复:杀孤儿

1
2
Stop-Process -Id 23388 -Force
Get-NetTCPConnection -LocalPort (20170..20172) -State Listen # → 无监听,端口已释放

端口释放后回 Web UI 点"启动"即恢复。


四、根因与防复发

根因:nssm 服务配了 AppExit Default Restart,但当 v2rayA 自身崩溃/异常退出(而非 nssm 主动停服务)时,nssm 的进程树回收不生效,子进程 core 被留下成孤儿,霸着入站端口,下次启动必撞车。

防复发:给 nssm 加事件钩子,在应用退出后、以及下次启动前,都清一遍残留 core:

1
2
3
4
$n = 'D:\Program Files (x86)\v2raya\nssm.exe'
& $n set v2raya AppEvents Exit/Post 'taskkill /F /IM v2ray.exe' # 退出后清孤儿
& $n set v2raya AppEvents Start/Pre 'taskkill /F /IM v2ray.exe' # 启动前再清一遍(双保险)
& $n set v2raya AppKillProcessTree 1 # 停服务时杀进程树

因为本机只有 v2rayA 会拉起 v2ray.exe,且 Start/Pre 时服务尚未启动、不存在正常 core,所以按名 taskkill 是安全的。


小结

  • Web UI 点启动弹错 ≠ 网络/订阅问题;先看进程与日志。

  • Only one usage of each socket address = 端口被占;用 Get-NetTCPConnection -State Listen 定位占用者。

  • 服务型部署要考虑子进程回收:崩溃退出留下的孤儿最阴险,用 nssm 事件钩子兜底。

注:v2rayA 的机场订阅链接带有个人 token,属敏感信息,本文已省略。


延伸阅读