找回密码
 立即注册
首页 业界区 安全 记录 Windows系统开启hyper-v ,部分端口被保留,导致端 ...

记录 Windows系统开启hyper-v ,部分端口被保留,导致端口不能使用而报错的问题

溜椎干 2 小时前
一、出现的问题

1、最近,部分客户在反馈,升级的过程中,偶尔出现升级的时候,开启IPC失败。观察了日志,是启动进程键通信的时候,服务的端口监听的时候,无法访问。这个个问题很是诡异
1.png

 
2.jpeg

 
二、问题排查

1、使用 “netstat -ano | findstr 端口” 的命令,发现该端口是没有进程占用的
3.png

 2、观察了我们获取可用端口的代码,是有判断端口是否被某些进程占用的过滤参数的,而且报错的不是在这个函数,而是已经拿到了端口后,做端口监听才抛出了如上的异常日志
  1.   private bool IsPortInUse(int port)
  2.         {
  3.             var properties = IPGlobalProperties.GetIPGlobalProperties();
  4.             IPEndPoint[] tcpListeners = properties.GetActiveTcpListeners();
  5.             IPEndPoint[] udpListeners = properties.GetActiveUdpListeners();
  6.             TcpConnectionInformation[] connections = properties.GetActiveTcpConnections();
  7.             return tcpListeners.Any(p => p.Port == port)
  8.                    || udpListeners.Any(p => p.Port == port)
  9.                    || connections.Any(c => c.LocalEndPoint.Port == port);
  10.         }
复制代码
3、搜索网上的出现的相同的问题,大多都指向了 开启了 hyper-v之后,端口被系统保留了。
解决 Windows 10 端口被 Hyper-V 随机保留(占用)的问题 | 一个兆基
4.png

5.jpeg

 4、开启hyper-v之后,使用 “netsh int ipv4 show excludedportrange protocol=tcp” 的命令,确实可以看到,好多段的端口范围都被排除了。
也就是说,如果只判断了端口是否被占用,但是端口没有进程占用,但是获取的端口又在排除的范围之内,一旦把该排除的端口做端口监听,就会报错。
6.png

 三、解决问题

1、简单但是不一定正确的方法,可以在远程客户的机器上临时解决使用(需要管理员身份)
 运行 net stop winnat 停止 winnat 服务,然后再运行 net start winnat 启动 winnat 服务。
  1. net stop winnat
  2. net start winnat
复制代码
2、重新设置TCP的动态端口范围(需要管理员身份),修改完需要重启电脑
  1. netsh int ipv4 set dynamic tcp start=49152 num=16384
  2. netsh int ipv6 set dynamic tcp start=49152 num=16384
复制代码
3、在代码上动态过滤掉被占用或者被保留的端口
[code] internal class ComputePortService {     public  int DefaultIpcPort { get; set; } = 18743;     ///      /// 获取有效的IPC端口     ///      ///      ///      public int GetValidIpcPort()     {         //获取保留端口范围         var excludedPortRange = GetExcludedPortRange();         for (int i = 0; i < 10000; i++)         {             var port = DefaultIpcPort + i;             if (port >= 65535)             {                 return 0;             }             bool isInUse = IsPortInUse(port, excludedPortRange);             Console.WriteLine($"{port} 占用结果:{isInUse}");             if (!isInUse)             {                 return port;             }         }         Console.WriteLine("No available IPC port found.");         return 0;     }     private bool IsPortInUse(int port, List excludePorts)     {         if (excludePorts.Any(excludePort => port >= excludePort.StartPort && port  p.Port == port)                                || udpListeners.Any(p => p.Port == port)                                || connections.Any(c => c.LocalEndPoint.Port == port);     }     ///      /// 获取保留端口     ///      ///      private List GetExcludedPortRange()     {         var excludedRanges = new List();         try         {             var encoding = GetSystemConsoleEncoding();             // 配置 netsh 命令启动信息             var processStartInfo = new ProcessStartInfo             {                 FileName = "netsh.exe",                 Arguments = "int ipv4 show excludedportrange protocol=tcp",                 RedirectStandardOutput = true, // 捕获命令输出                 RedirectStandardError = true,  // 捕获错误信息                 UseShellExecute = false,       // 必须为 false 才能重定向输出                 CreateNoWindow = true,         // 后台执行,不显示命令窗口                 // 关键:适配中文/英文系统编码,避免乱码                 StandardOutputEncoding = encoding,                 StandardErrorEncoding = encoding             };             // 启动进程并执行命令             using var process = new Process { StartInfo = processStartInfo };             process.Start();             var output = process.StandardOutput.ReadToEnd();             var error = process.StandardError.ReadToEnd();             process.WaitForExit();             // 处理命令执行失败(如 netsh 命令不存在,理论上 Windows 都内置)             if (process.ExitCode != 0)             {                 Console.WriteLine($"netsh 命令执行失败:{error}(退出码:{process.ExitCode}");                 return excludedRanges;             }             Console.WriteLine($"获取保留端口的命令结果:{output}");             // 解析命令输出,提取端口范围             excludedRanges = PortConverter(output);             return excludedRanges;         }         catch (Exception ex)         {             Console.WriteLine($"获取预留端口范围失败:{ex.Message}", ex);             return excludedRanges;         }     }     ///      /// 解析 netsh 命令输出,提取预留端口范围     ///      /// netsh 命令原始输出     /// 解析后的端口范围列表     private List PortConverter(string output)     {         var ranges = new List();         if (string.IsNullOrWhiteSpace(output))             return ranges;         var regex = new Regex(@"\s+(\d+)\s+(\d+)", RegexOptions.Multiline | RegexOptions.IgnoreCase);         var matches = regex.Matches(output);         foreach (Match match in matches)         {             // 安全解析端口号(确保是合法端口范围)             if (match.Groups.Count == 3                 && int.TryParse(match.Groups[1].Value, out var startPort)                 && int.TryParse(match.Groups[2].Value, out var endPort)                 && startPort >= 0 && endPort >= startPort && endPort

相关推荐

您需要登录后才可以回帖 登录 | 立即注册