问题描述
在 Windows 上启动 .NET Aspire AppHost 项目时,Aspire Dashboard 显示服务启动失败,控制台输出以下错误:
Aspire.Hosting.Dcp.dcpctrl.ServiceReconciler[0] could not start the proxy {"ServiceName": {"name":"api-https"}, "Reconciliation": 17, "error": "could not start the proxy for the service: listen tcp [::1]:53209: bind: An attempt was made to access a socket in a way forbidden by its access permissions."}
错误截图:
关键信息:
- 错误发生在
listen tcp [::1]:53209: bind— 端口53209无法绑定 - 错误码含义:操作系统拒绝了对该端口的访问,而非"端口已被占用"
- 使用
netstat -ano | findstr 53209检查,发现没有任何进程占用该端口
这就引出了一个问题:端口没被占用,为什么绑定失败?
问题解答
根因分析
这个问题的根本原因是 Windows Hyper-V(或 WSL2)的动态端口保留机制。
Windows 在启用 Hyper-V 后(Docker Desktop、WSL2、Windows Sandbox 等功能都会启用 Hyper-V),系统的 TCP/IP 协议栈会随机保留一批端口范围供 Hyper-V 虚拟交换机使用。这些端口对普通应用程序是不可用的,即使没有任何进程在监听。
诊断步骤
第 1 步:查看系统保留的端口范围
netsh interface ipv4 show excludedportrange protocol=tcp
输出示例:
使用 tcp 端口以考虑排除的范围 开始端口 结束端口 ---------- ---------- 49670 49769 49870 49969 53113 53212 * <-- 当前Aspire应用的端口在这个范围内! 65228 65327 65328 65427
第 2 步:确认服务所使用的端口是否落在保留范围内
本当前的Apsire项目中,三个服务的端口配置(launchSettings.json):
| 服务 | HTTPS 端口 | HTTP 端口 | 是否在保留范围 |
| API | 53209 | 53211 | ✅ 在 53113–53212 内 |
| Web | 53208 | 53210 | ✅ 在 53113–53212 内 |
| Admin | 53205 | 53206 | ✅ 在 53113–53212 内 |
所有 6 个端口全部被系统保留,因此 Aspire 的 DCP(Distributed Computing Platform)代理无法为任何服务创建监听。
解决方案
方案一:更换端口(推荐 ✅)
将服务端口改到一个不在保留范围内的区间。推荐使用 7xxx 范围(ASP.NET Core 新项目的默认约定范围):
修改每个服务的 Properties/launchSettings.json:
// src/MyBlog.Api/Properties/launchSettings.json { "profiles": { "MyBlog.Api": { "applicationUrl": "https://localhost:7101;http://localhost:7102" } } }
// src/MyBlog.Web/Properties/launchSettings.json { "profiles": { "MyBlog.Web": { "applicationUrl": "https://localhost:7201;http://localhost:7202" } } }
// src/MyBlog.Admin/Properties/launchSettings.json { "profiles": { "MyBlog.Admin": { "applicationUrl": "https://localhost:7301;http://localhost:7302" } } }
当然,还有其它的方案也可以缓解此问题。 接下来的方案二,三,虽然没有经过验证,但根据AI所提供的命令和描述信息,预期是可以成功的。
方案二:释放 Hyper-V 保留的端口(需要管理员权限 + 重启)
# 以管理员身份运行 # 1. 停止 Hyper-V 网络服务 net stop winnat # 2. 重新启动 net start winnat
⚠️ 注意:此方法效果是临时的,系统重启后 Hyper-V 会重新随机保留端口范围。
方案三:永久排除特定端口不被 Hyper-V 保留
# 以管理员身份运行 # 先停止 winnat net stop winnat # 保留你需要的端口范围(排除 Hyper-V 占用) netsh int ipv4 add excludedportrange protocol=tcp startport=7100 numberofports=10 netsh int ipv4 add excludedportrange protocol=tcp startport=7200 numberofports=10 netsh int ipv4 add excludedportrange protocol=tcp startport=7300 numberofports=10 # 重启 winnat net start winnat
附录: 如何选择端口
选择端口时,遵循以下原则:
- 避开 1024 以下:系统保留端口
- 避开 49152–65535:Windows 动态端口范围(
IANA ephemeral ports),Hyper-V 最常在此区间保留 - 推荐 5000–8000:ASP.NET Core 常用范围,较少被系统保留
- 修改前先检查:运行
netsh interface ipv4 show excludedportrange protocol=tcp确认端口可用
额外说明
通过 Aspire AppHost 启动时,Aspire 的 DCP 会为每个服务创建代理(proxy),代理端口来自 launchSettings.json 中的 applicationUrl。如果这些端口不可用,就会出现本文描述的错误。
参考资料
- Microsoft 官方文档 - TCP/IP 端口耗尽疑难解答
https://learn.microsoft.com/zh-cn/troubleshoot/windows-client/networking/tcp-ip-port-exhaustion-troubleshooting - Docker Desktop 已知问题 - Hyper-V 保留端口
https://github.com/docker/for-win/issues/3171 - .NET Aspire 文档 - DCP 网络配置
https://learn.microsoft.com/zh-cn/dotnet/aspire/fundamentals/networking-overview - Stack Overflow - "An attempt was made to access a socket in a way forbidden"
https://stackoverflow.com/questions/48478869
当在复杂的环境中面临问题,格物之道需:浊而静之徐清,安以动之徐生。 云中,恰是如此!