【Azure Developer】.NET Aspire 启动报错:listen tcp bind: An attempt was made to access a socket in a way forbidden by its access permissions

问题描述

在 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

附录: 如何选择端口

选择端口时,遵循以下原则:

  1. 避开 1024 以下:系统保留端口
  2. 避开 49152–65535:Windows 动态端口范围(IANA ephemeral ports),Hyper-V 最常在此区间保留
  3. 推荐 5000–8000:ASP.NET Core 常用范围,较少被系统保留
  4. 修改前先检查:运行 netsh interface ipv4 show excludedportrange protocol=tcp 确认端口可用

额外说明 通过 Aspire AppHost 启动时,Aspire 的 DCP 会为每个服务创建代理(proxy),代理端口来自 launchSettings.json 中的 applicationUrl。如果这些端口不可用,就会出现本文描述的错误。


参考资料

  1. Microsoft 官方文档 - TCP/IP 端口耗尽疑难解答 https://learn.microsoft.com/zh-cn/troubleshoot/windows-client/networking/tcp-ip-port-exhaustion-troubleshooting

  2. Docker Desktop 已知问题 - Hyper-V 保留端口 https://github.com/docker/for-win/issues/3171

  3. .NET Aspire 文档 - DCP 网络配置 https://learn.microsoft.com/zh-cn/dotnet/aspire/fundamentals/networking-overview

  4. Stack Overflow - "An attempt was made to access a socket in a way forbidden" https://stackoverflow.com/questions/48478869


正在加载评论...