Hyper-Vを有効にしたWindowsシステムでポート予約問題が発生する事象の記録

問題概要

Hyper-Vを有効化したWindows環境において、特定のネットワークポートがシステム予約領域に含まれるため、アプリケーションがポート使用時にエラーを発生させる事象が確認されています。特にIPC通信の確立時にポートリッスンに失敗する症状が報告されています。

診断手順

  1. netstat -ano | findstr [ポート番号]でポート使用状況を確認しても、該当ポートは空き状態に表示される
  2. ポート検出ロジックのコードレビューで、アクティブな接続検知機能に問題なしと確認済み
bool CheckPortAvailability(int port) {
    var props = IPGlobalProperties.GetIPGlobalProperties();
    return props.GetActiveTcpListeners().Any(p => p.Port == port) ||
           props.GetActiveUdpListeners().Any(p => p.Port == port) ||
           props.GetActiveTcpConnections().Any(c => c.LocalEndPoint.Port == port);
}

根本原因

Hyper-Vの有効化により、netsh int ipv4 show excludedportrange protocol=tcpコマンドで確認できるように、複数のポート範囲がシステム予約領域として除外されていることが判明。この予約領域内のポートは、プロセス未使用状態であっても実際には使用不可となる。

解決策

一時的措置(管理者権限必要)

net stop winnat
net start winnat

永続的設定変更(再起動必要)

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

コードレベルでの回避策

システム予約ポート範囲を取得し、ポート選定時にその範囲を除外する実装例:

class PortManager {
    public int BasePort { get; set; } = 18743;

    public int FindAvailablePort() {
        var reservedRanges = GetReservedPortRanges();
        for (int i = 0; i < 10000; i++) {
            int candidate = BasePort + i;
            if (candidate >= 65535) return 0;

            if (!IsPortReserved(candidate, reservedRanges) && 
                !CheckPortAvailability(candidate)) {
                return candidate;
            }
        }
        return 0;
    }

    List<PortRange> GetReservedPortRanges() {
        // netshコマンド実行と出力解析ロジック
        var ranges = new List<PortRange>();
        var process = new Process {
            StartInfo = new ProcessStartInfo {
                FileName = "netsh.exe",
                Arguments = "int ipv4 show excludedportrange protocol=tcp",
                RedirectStandardOutput = true,
                UseShellExecute = false,
                CreateNoWindow = true
            }
        };
        // 出力解析とPortRangeオブジェクト生成
        return ranges;
    }
}

動作検証例

// 使用例
var manager = new PortManager();
int availablePort = manager.FindAvailablePort();
Console.WriteLine($"確保済みポート: {availablePort}");

タグ: C# Hyper-V Windows ネットワーク構成 ポート予約

5月18日 20:39 投稿