J'effectue des tests d'intégration avec le service API REST.
Le problème est que parfois, le port codé en dur n’est pas libre au moment où le test commence pour la prochaine fois. Parce qu'il a été ouvert par le test précédent et n'est pas encore fermé par le système.
J'utilise OWIN, l'application est fermée au moment du prochain test.
Pourriez-vous s'il vous plaît me suggérer un bon moyen de déterminer un port libre sur le système sans l'ouvrir à l'avance puis le fermer? Ou dire que ce n'est pas possible.
Parce qu'il ne peut pas encore être libéré par le système, comme cela se produit déjà.
Au lieu de answer de TempoClick, nous pouvons utiliser la méthode IPGlobalProperties.GetActiveTcpListeners()
pour vérifier si un port est disponible - sans essayer de l'ouvrir à l'avance. GetActiveTcpListeners()
renvoie tous les écouteurs TCP actifs sur le système. Nous pouvons donc l'utiliser pour déterminer si un port est libre ou non.
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);
}
Notez que GetActiveTcpListeners()
ne renvoie pas de points de terminaison UDP en écoute, mais nous pouvons les obtenir avec GetActiveUdpListeners()
.
Vous pouvez donc commencer avec le port par défaut (ou sélectionner une valeur aléatoire) et continuer à incrémenter jusqu'à ce que vous trouviez un port libre avec la méthode IsFree
.
int NextFreePort(int port = 0)
{
port = (port > 0) ? port : new Random().Next(1, 65535);
while (!IsFree(port))
{
port += 1;
}
return port;
}
Un test simple:
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;
}
}
Une approche différente consiste à utiliser le port zéro. Dans ce cas, le système sélectionnera un port libre aléatoire dans la plage de ports dynamiques. Nous pouvons obtenir le numéro de ce port à partir de la propriété LocalEndpoint
.
TcpListener server = new TcpListener(IPAddress.Loopback, 0);
server.Start();
int port = ((IPEndPoint)server.LocalEndpoint).Port;
Console.WriteLine(port);
Pour obtenir un port gratuit
static int FreePort()
{
TcpListener l = new TcpListener(IPAddress.Loopback, 0);
l.Start();
int port = ((IPEndPoint)l.LocalEndpoint).Port;
l.Stop();
return port;
}