web-dev-qa-db-fra.com

Recherchez le prochain port TCP dans .NET

Je veux créer un nouveau point de terminaison net.tcp: // localhost: x/Service pour un appel de service WCF, avec un nouveau port ouvert TCP TCP attribué dynamiquement).

Je sais que TcpClient attribuera un nouveau port côté client lorsque j'ouvrirai une connexion à un serveur donné.

Existe-t-il un moyen simple de trouver le prochain port TCP TCP ouvert dans .NET?

J'ai besoin du nombre réel, pour pouvoir construire la chaîne ci-dessus. 0 ne fonctionne pas, car je dois passer cette chaîne à un autre processus, afin de pouvoir rappeler sur ce nouveau canal.

61
TheSeeker

Voici ce que je cherchais:

static int FreeTcpPort()
{
  TcpListener l = new TcpListener(IPAddress.Loopback, 0);
  l.Start();
  int port = ((IPEndPoint)l.LocalEndpoint).Port;
  l.Stop();
  return port;
}
118
TheSeeker

Utilisez un numéro de port de 0. La pile TCP allouera le prochain libre.

19
Jerub

Ouvrez d'abord le port, puis donnez le numéro de port correct à l'autre processus.

Sinon, il est toujours possible qu'un autre processus ouvre le port en premier et vous en avez encore un autre.

9
jan.vdbergh

C'est une solution comparable à la réponse acceptée de TheSeeker. Bien que je pense que c'est plus lisible:

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

    private static readonly IPEndPoint DefaultLoopbackEndpoint = new IPEndPoint(IPAddress.Loopback, port: 0);

    public static int GetAvailablePort()
    {
        using (var socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
        {
            socket.Bind(DefaultLoopbackEndpoint);
            return ((IPEndPoint)socket.LocalEndPoint).Port;
        }
    }
7
Eric Boumendil

Si vous voulez simplement donner un port de départ et le laisser vous revenir le prochain TCP disponible, utilisez un code comme celui-ci:

public static int GetAvailablePort(int startingPort)
{
    var portArray = new List<int>();

    var properties = IPGlobalProperties.GetIPGlobalProperties();

    // Ignore active connections
    var connections = properties.GetActiveTcpConnections();
    portArray.AddRange(from n in connections
                        where n.LocalEndPoint.Port >= startingPort
                        select n.LocalEndPoint.Port);

    // Ignore active tcp listners
    var endPoints = properties.GetActiveTcpListeners();
    portArray.AddRange(from n in endPoints
                        where n.Port >= startingPort
                        select n.Port);

    // Ignore active UDP listeners
    endPoints = properties.GetActiveUdpListeners();
    portArray.AddRange(from n in endPoints
                        where n.Port >= startingPort
                        select n.Port);

    portArray.Sort();

    for (var i = startingPort; i < UInt16.MaxValue; i++)
        if (!portArray.Contains(i))
            return i;

    return 0;
}
4
zumalifeguard

Si vous souhaitez obtenir un port libre dans une plage spécifique afin de l'utiliser comme port local/point de terminaison:

private int GetFreePortInRange(int PortStartIndex, int PortEndIndex)
{
    DevUtils.LogDebugMessage(string.Format("GetFreePortInRange, PortStartIndex: {0} PortEndIndex: {1}", PortStartIndex, PortEndIndex));
    try
    {
        IPGlobalProperties ipGlobalProperties = IPGlobalProperties.GetIPGlobalProperties();

        IPEndPoint[] tcpEndPoints = ipGlobalProperties.GetActiveTcpListeners();
        List<int> usedServerTCpPorts = tcpEndPoints.Select(p => p.Port).ToList<int>();

        IPEndPoint[] udpEndPoints = ipGlobalProperties.GetActiveUdpListeners();
        List<int> usedServerUdpPorts = udpEndPoints.Select(p => p.Port).ToList<int>();

        TcpConnectionInformation[] tcpConnInfoArray = ipGlobalProperties.GetActiveTcpConnections();
        List<int> usedPorts = tcpConnInfoArray.Where(p=> p.State != TcpState.Closed).Select(p => p.LocalEndPoint.Port).ToList<int>();

        usedPorts.AddRange(usedServerTCpPorts.ToArray());
        usedPorts.AddRange(usedServerUdpPorts.ToArray());

        int unusedPort = 0;

        for (int port = PortStartIndex; port < PortEndIndex; port++)
        {
            if (!usedPorts.Contains(port))
            {
                unusedPort = port;
                break;
            }
        }
        DevUtils.LogDebugMessage(string.Format("Local unused Port:{0}", unusedPort.ToString()));

        if (unusedPort == 0)
        {
            DevUtils.LogErrorMessage("Out of ports");
            throw new ApplicationException("GetFreePortInRange, Out of ports");
        }

        return unusedPort;
    }
    catch (Exception ex)
    {
        string errorMessage = ex.Message;
        DevUtils.LogErrorMessage(errorMessage);
        throw;
    }
}


private int GetLocalFreePort()
{
    int hemoStartLocalPort = int.Parse(DBConfig.GetField("Site.Config.hemoStartLocalPort"));
    int hemoEndLocalPort = int.Parse(DBConfig.GetField("Site.Config.hemoEndLocalPort"));
    int localPort = GetFreePortInRange(hemoStartLocalPort, hemoEndLocalPort);
    DevUtils.LogDebugMessage(string.Format("Local Free Port:{0}", localPort.ToString()));
    return localPort;
}


public void Connect(string Host, int port)
{
    try
    {
        // Create socket
        Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
        //socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);

        var localPort = GetLocalFreePort();
        // Create an endpoint for the specified IP on any port
        IPEndPoint bindEndPoint = new IPEndPoint(IPAddress.Any, localPort);

        // Bind the socket to the endpoint
        socket.Bind(bindEndPoint);

        // Connect to Host
        socket.Connect(IPAddress.Parse(Host), port);

        socket.Dispose();
    }
    catch (SocketException ex)
    {
        // Get the error message
        string errorMessage = ex.Message;
        DevUtils.LogErrorMessage(errorMessage);
    }
}


public void Connect2(string Host, int port)
{
    try
    {
        // Create socket

        var localPort = GetLocalFreePort();

        // Create an endpoint for the specified IP on any port
        IPEndPoint bindEndPoint = new IPEndPoint(IPAddress.Any, localPort);

        var client = new TcpClient(bindEndPoint);
        //client.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true); //will release port when done

        // Connect to the Host
        client.Connect(IPAddress.Parse(Host), port);

        client.Close();
    }
    catch (SocketException ex)
    {
        // Get the error message
        string errorMessage = ex.Message;
        DevUtils.LogErrorMessage(errorMessage);
    }
}
1
yoavs