解决 Windows 10 端口被 Hyper-V 随机保留(占用)的问题

大概从半年前开始,我发现我的代理软件配置的端口有时会不能用,软件提示「没有权限访问端口」。这个问题会在什么时候出现完全随机,没有任何规律。对于这个问题,有时候重启可以解决,有时候重启好几次才能解决,并且如果运气不好,可能重启几次后这些端口还是不能用……

这让我非常困惑,我给代理软件开了管理员权限,但没有效果。我使用 netstat -ano 想看看这些端口被什么程序占用,却一无所获。当时,我误以为是代理软件出了一些神秘问题,在 google 无果后,因为大多数时候重启都能解决,我就没有再管。

直到前两天,我在做 Web 开发时,发现在 Windows 10 中使用 localhost:8088 死活访问不了 WSL 2 的 8088 端口。一开始我以为是 WSL 2 默认的端口转发出错了,便用 netsh interface portproxy 重新指定了端口转发,但还是访问不了。我又猜想可能是 WSL 2Ubuntu 的防火墙规则有问题,但排查后发现不是。我又怀疑是 Windows 10 的防火墙设置有问题,但仔细核对后发现确实没有问题。正当我百思不得其解时,我随手把端口号换成了 3000,发现居然能用了。并且在我再一次重启电脑之后,发现之前不能用的 8088 也又能用了。

这个灵异问题让我顿时联想到了半年前出现的那个代理软件端口不能用的问题,我试着又重启了几次,发现刚刚能用的 8088 端口又不能用了。面对这种奇葩情况,我只能推断可能是 Windows 10 因为某些原因,会随机保留这些端口号,不让用户使用。

但老重启也不是个事儿,这次我找对了搜索关键字,一番 google 后终于搞明白了问题的成因,并解决了这个困扰我半年之久的问题。

1. 问题背景

这个问题的背景分为两部分:

    1. Windows 中有一个「TCP 动态端口范围」,处在这个范围内的端口,有时候会被一些服务占用。在 Windows Vista(或 Windows Server 2008)之前,动态端口范围是 10255000;在 Windows Vista(或 Windows Server 2008)之后,新的默认起始端口为 49152,新的默认结束端口为 65535
    2. 如果安装了 Hyper-V,那么 Hyper-V 会为容器宿主网络服务(Windows Container Host Networking Service)随机保留一些端口号使用。

正常情况下,Hyper-V 虽然会在「TCP 动态端口范围」中随机挑一些端口号保留(占用),不过保留的端口号普遍比较大,就算保留几百、几千个也影响不大。但是,Windows 自动更新有时会出错,导致这个范围的起始端口被重置为 1024……这可就麻烦了,一些常用端口动不动就因为被保留而无法使用了。

使用命令 netsh int ipv4 show dynamicport tcp 可以查看目前「TCP 动态端口」的范围,如图 1 所示。

图 1 查看目前「TCP动态端口」的范围

图 1 查看目前「TCP 动态端口」的范围

这只是一个「待选择」范围,并不代表其中的所有端口都会被保留,只是有一部分会被 Hyper-V 征用。使用 netsh int ipv4 show excludedportrange protocol=tcp 命令可以查看当前所有已经被征用了的端口,如图 2 所示。

图 2 当前所有已经被征用了的端口

图 2 当前所有已经被征用了的端口

如果这些被征用的端口范围随机挑选到 808880003000 等 Web 开发常用端口,那开发就会受到影响;如果挑选到其他应用软件要调用的端口,那这些应用软件就会受到影响,可以说非常坑爹了……

在说正确的解决方法前,我们先说一个在 Stack Overflow 上看到的错误解决方法,这个方法还在好几个地方被提到过。

2. 错误的解决方法

错误的解决方法是,运行 net stop winnat 停止 winnat 服务,然后再运行 net start winnat 启动 winnat 服务。

这个方法本质上就是重启电脑的简化版……让 Hyper-V 再随机初始化一些端口保留,如果正好没随机到要用的端口,那一次成功。如果还是随机到了要用的端口,那就只能多来几次。

在那个问题的回答下,我看到有一些网友说「对我有用」,也有一些网友说「对我没用」,原因就是这个方法解决问题的概率完全是随机的……

3. 正确的解决方法

正确的解决方法很简单,就是重新设置一下「TCP 动态端口范围」,让 Hyper-V 只在我们设定的范围内保留端口即可。可以以管理员权限运行下面的命令,将「TCP 动态端口范围」重新设定为 49152-65535。如果你觉得这个范围太大,还可以改小一点。

netsh int ipv4 set dynamic tcp start=49152 num=16384
netsh int ipv6 set dynamic tcp start=49152 num=16384

然后重启电脑即可。

重启电脑后,再运行命令 netsh int ipv4 show dynamicport tcp 查看动态端口范围,发现确实已经修改为了 49152-65535。现在只有这个范围内的端口可能会被保留了,基本不会影响日常使用(图 3)。

图 3 重启后再查看动态端口范围

图 3 重启后再查看动态端口范围

参考文献

[1] Hung-Yi Loo. WSL2, Hyper-V & Reserved Ports[G/OL]. Hung-Yi’s Journal, 2020(20200831)[2020-08-31]. https://hungyi.net/posts/wsl2-reserved-ports/

[2] cpietrzykowski. Unable to bind ports: Docker-for-Windows & Hyper-V excluding but not using important port ranges[G/OL]. Github, 2019(20191116)[2019-11-16]. https://github.com/docker/for-win/issues/3171#issuecomment-554587817

[3] Han Liang, olprod. 自 Vista 和 Windows Server 2008 以来 TCP/IP 的默认 Windows 端口范围已更改 [G/OL]. Microsoft Docs, 2021(20210925)[2021-09-25]. https://docs.microsoft.com/zh-CN/troubleshoot/windows-server/networking/default-dynamic-port-range-tcpip-chang

解决 Windows 10 端口被 Hyper-V 随机保留(占用)的问题》有2个想法

发表回复

您的电子邮箱地址不会被公开。