我正在用REST API服务运行一些集成测试。问题是有时在下一次测试开始时,硬编码的端口并不空闲。因为它已经被之前的测试打开了,但还没有被系统关闭。
我使用的是OWIN,在下一次测试开始的那一刻,应用程序就会被关闭。
请您给我一个好的方法来确定系统的空闲端口。不经意间 然后关闭它?或者说这是不可能的。
因为它可能还没有被系统释放,就像已经发生的一样。
作为TempoClick的替代方案 回答,我们可以使用 IPGlobalProperties.GetActiveTcpListeners()
方法来测试一个端口是否可用--而不需要事先尝试打开它。GetActiveTcpListeners()
返回系统中所有活跃的TCP监听器,因此我们可以用它来判断一个端口是否可用。
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);
}
请注意 GetActiveTcpListeners()
不返回监听的UDP端点,但我们可以用 GetActiveUdpListeners()
.
所以,你可以从默认的端口开始 (或者选择一个随机的值),然后不断地增加,直到你找到一个可以用 IsFree
方法。
int NextFreePort(int port = 0)
{
port = (port > 0) ? port : new Random().Next(1, 65535);
while (!IsFree(port))
{
port += 1;
}
return port;
}
一个简单的测试。
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;
}
}
另一种方法是使用零端口 在这种情况下,系统会从动态端口范围中随机选择一个空闲端口。我们可以从这个端口的编号中得到 LocalEndpoint
财产。
TcpListener server = new TcpListener(IPAddress.Loopback, 0);
server.Start();
int port = ((IPEndPoint)server.LocalEndpoint).Port;
Console.WriteLine(port);
要获得一个免费的端口
static int FreePort()
{
TcpListener l = new TcpListener(IPAddress.Loopback, 0);
l.Start();
int port = ((IPEndPoint)l.LocalEndpoint).Port;
l.Stop();
return port;
}