wake-up-neo.net

Holen Sie sich zufällig geöffneten Port für Tests

Ich führe einige Integrationstests mit dem API-Service REST durch.
Das Problem ist, dass manchmal der fest codierte Port zum Zeitpunkt des nächsten Teststarts nicht frei ist. Weil es vom vorherigen Test geöffnet und vom System noch nicht geschlossen wurde.

Ich benutze OWIN, die Anwendung wird zum Zeitpunkt des nächsten Teststarts beendet.

Könnten Sie mir bitte einen guten Weg vorschlagen, um einen freien Port auf dem System zu bestimmen ohne ihn vorher zu öffnen und dann zu schließen? Oder sagen, dass es nicht möglich ist.

Weil es noch nicht vom System freigegeben werden konnte, so wie es schon passiert.

6
cassandrad

Alternativ zu TempoClicks answer können wir mit der Methode IPGlobalProperties.GetActiveTcpListeners() testen, ob ein Port verfügbar ist - ohne ihn vorher zu öffnen. GetActiveTcpListeners() gibt alle aktiven TCP Listener auf dem System zurück. Auf diese Weise können wir feststellen, ob ein Port frei ist oder nicht.

public bool IsFree(int port)
{
    IPGlobalProperties properties = IPGlobalProperties.GetIPGlobalProperties();
    IPEndPoint[] listeners = properties.GetActiveTcpListeners();
    int[] openPorts = listeners.Select(item => item.Port).ToArray<int>();
    return openPorts.All(openPort => openPort != port);
}

Beachten Sie, dass GetActiveTcpListeners() keine empfangsbereiten UDP-Endpunkte zurückgibt, aber wir können sie mit GetActiveUdpListeners() abrufen.

Sie können also mit dem Standardport beginnen (oder einen zufälligen Wert auswählen) und so lange inkrementieren, bis Sie mit der Methode IsFree einen freien Port finden.

int NextFreePort(int port = 0) 
{
    port = (port > 0) ? port : new Random().Next(1, 65535);
    while (!IsFree(port)) 
    {
        port += 1;
    }
    return port;
}

Ein einfacher Test:

using System;
using System.Net;
using System.Net.Sockets;
using System.Net.NetworkInformation;
using System.Linq;

class Test
{
    static void Main(string[] args)
    {
        int port = 1000;
        Console.WriteLine(IsFree(port));
        TcpListener server = new TcpListener(IPAddress.Parse("127.0.0.1"), port);
        server.Start();   
        Console.WriteLine(IsFree(port));
        Console.WriteLine(NextFreePort(port));
    }

    static bool IsFree(int port)
    {
        IPGlobalProperties properties = IPGlobalProperties.GetIPGlobalProperties();
        IPEndPoint[] listeners = properties.GetActiveTcpListeners();
        int[] openPorts = listeners.Select(item => item.Port).ToArray<int>();
        return openPorts.All(openPort => openPort != port);
    }

    static int NextFreePort(int port = 0) {
        port = (port > 0) ? port : new Random().Next(1, 65535);
        while (!IsFree(port)) {
            port += 1;
        }
        return port;
    }
}

Ein anderer Ansatz ist die Verwendung von Port Null. In diesem Fall wählt das System einen zufälligen freien Port aus dem dynamischen Portbereich aus. Die Nummer dieses Ports können wir aus der Eigenschaft LocalEndpoint ermitteln.

TcpListener server = new TcpListener(IPAddress.Loopback, 0);
server.Start();
int port = ((IPEndPoint)server.LocalEndpoint).Port;
Console.WriteLine(port);
2
t.m.adam

Um einen freien Hafen zu bekommen

static int FreePort()
{
  TcpListener l = new TcpListener(IPAddress.Loopback, 0);
  l.Start();
  int port = ((IPEndPoint)l.LocalEndpoint).Port;
  l.Stop();
  return port;
}
2
TempoClick