对于 Windows 10 及 Windows 11,当启用 Hyper-V 或者虚拟机平台后,Windows NAT 服务会随机保留一些端口以便于提供 NAT (网络地址转换) 服务,以实现虚拟机的上网。这些端口范围是随机确定的,因此很容易导致开发时遇到端口占用问题。比如会遇到以下错误:
- Error: listen EADDRINUSE: address already in use :::3000
- 以一种访问权限不允许的方式做了一个访问套接字的尝试。
- An attempt was made to access a socket in a way forbidden by its access permissions
除此以外,还可能会遇到明明服务启动成功但是却访问不了的问题,这也很有可能是因为端口被 WinNAT 给占了。
解决方案
网络上普遍建议重新设置一下「TCP 动态端口范围」(如文章 解决 Windows 10 端口被 Hyper-V 随机保留(占用)的问题 ),但是这种方法并不总是有效,因为你并不知道自己未来会即兴用到哪些端口,如果端口分的少了,又会导致其他问题,比如因为可用端口不够用而妨碍上网。
好在,Windows有一个很有趣的特性,就是用户可以 自行保留端口 给用户态程序使用。被用户保留的端口只能被用户态程序分配使用,却不能被内核驱动程序和服务使用。比如我设置保留 1080 端口后,Clash 这类普通用户态程序可以直接申请到这个端口,但是 IIS、WinNAT 等内核驱动程序和服务试图申请时却会被系统拒绝。这样一来,就可以避免端口被 WinNAT 占用的问题。
操作步骤
- 以管理员身份打开命令提示符(Win+X,A)。
- 运行以下命令,查看目前「TCP 动态端口」的范围
netsh int ipv4 show dynamicport tcp
得到类似如下的输出:
协议 tcp 端口排除范围
开始端口 结束端口
---------- --------
6 6
80 80
1080 1088 *
5357 5357
7058 7058
8000 8079 *
50000 50059 *
53317 53317 *
56052 56151
56152 56251
56252 56351
56352 56451
56452 56551
... 省略 ...
* - 管理的端口排除。
需要注意一下这个输出:
- 首先前几行列出(表中为 6、80)的是 IIS 使用的端口。如果你的端口是在这里被占用了,那么你需要看看 IIS 那边是怎么个事。
- 然后,有
*
标记的是我们自行保留的端口,其他的就是被 Windows NAT 服务随机保留的端口。 - 剩下的,就是 Windows NAT 服务随机保留的端口。这些端口是不固定的,每次重启都会变。
- 暂时停止 WinNAT 服务
必须先停止 WinNAT 服务以释放被占用的端口。
net stop winnat
- 保留想要使用端口
startport
表示起始端口,numberofports
表示要保留的端口数量。比如保留 1080~1089 端口:
netsh int ipv4 add excludedportrange protocol=tcp startport=1080 numberofports=10
如果提示 另一个程序正在使用此文件,进程无法访问 ,请先关掉所有已占用这个范围的端口的程序。
- 重新启动 winnat 服务
net start winnat
- 完成
同理可以设置 UDP 的端口保留,但是 WinNAT 并不会占用 UDP 端口,因此一般不需要设置。通常也不需要设置 IPv6 的端口保留,因为 Windows 压根就不支持 IPv6 NAT / NAT66,自然不存在端口占用一说。
附:删除保留的端口
可以使用以下命令删除自行保留的端口:
netsh int ipv4 del excludedportrange protocol=tcp startport=1080 numberofports=9