[C#] 使用中のポートを取得し、空きポートを探す方法

2023-04-07 (金)

TCP, UDP の使用中のポートを全て取得する方法です。
アプリから動的に Web サーバーを立ち上げる際に、空きポートを指定する必要があったため、指定したポート番号以降の最初の空きポートを取得方法もメモします。

環境

  • .NET 7.0.202
  • C# 11.0
  • Visual Studio 2022 Version 17.5.3
  • Windows 10 Pro 64bit 22H2 19045.2728

実装

使用中のポートを取得する

using System.Collections.Generic;
using System.Net.NetworkInformation;

static IEnumerable<int> EnumerateActivePorts()
{
    var ipGlobalProperties = IPGlobalProperties.GetIPGlobalProperties();

    foreach (var connection in ipGlobalProperties.GetActiveTcpConnections())
    {
        yield return connection.LocalEndPoint.Port;
    }

    foreach (var tcpListener in ipGlobalProperties.GetActiveTcpListeners())
    {
        yield return tcpListener.Port;
    }

    foreach (var udpListener in ipGlobalProperties.GetActiveUdpListeners())
    {
        yield return udpListener.Port;
    }
}

指定したポート番号以降の最初の空きポートを取得する

using System.Collections.Generic;
using System.Linq;
using System.Net.NetworkInformation;

static int GetAvailablePort(int startPort)
{
    var ipGlobalProperties = IPGlobalProperties.GetIPGlobalProperties();

    var connections = ipGlobalProperties.GetActiveTcpConnections().Select(x => x.LocalEndPoint);
    var tcpListeners = ipGlobalProperties.GetActiveTcpListeners();
    var udpListeners = ipGlobalProperties.GetActiveUdpListeners();

    var activePorts = new HashSet<int>(connections
        .Concat(tcpListeners)
        .Concat(udpListeners)
        .Where(x => x.Port >= startPort)
        .Select(x => x.Port));

    for (var port = startPort; port <= 65535; port++)
    {
        if (!activePorts.Contains(port))
            return port;
    }

    return -1;
}

空きポートを自動取得する

using System.Net;
using System.Net.Sockets;

static int FindFreePort()
{
    using var socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
    socket.Bind(new IPEndPoint(IPAddress.Any, 0));
    var endPoint = (IPEndPoint?)socket.LocalEndPoint;
    return endPoint?.Port ?? -1;
}

注意

UWP や Azure 上では、以下のメソッドで例外が発生するようです。

IPGlobalProperties.GetActiveTcpConnections();
IPGlobalProperties.GetActiveTcpListeners();
IPGlobalProperties.GetActiveUdpListeners();

感謝

2023-04-07 (金)