我正在使用REST API服务运行一些集成测试。
问题在于,有时在下一次测试开始时,硬编码端口有时不可用。因为它是由先前的测试打开的,但尚未被系统关闭。
我使用OWIN,在下一次测试开始时,应用程序将关闭。
您能否建议我一种确定系统上的空闲端口的好方法,无需提前打开它然后关闭它?或者说这是不可能的。
因为它尚未被系统释放,就像已经发生的那样。
答案 0 :(得分:2)
获得免费端口
static int FreePort()
{
TcpListener l = new TcpListener(IPAddress.Loopback, 0);
l.Start();
int port = ((IPEndPoint)l.LocalEndpoint).Port;
l.Stop();
return port;
}
答案 1 :(得分:2)
作为TempoClick的answer的替代方法,我们可以使用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);
答案 2 :(得分:0)
以下单线(taken from this SO post)使用Python快速打开和关闭端口0上的套接字。在Python中执行此操作时,它会自动选择一个打开的端口,该端口会输出到屏幕上:
python -c 'import socket; s=socket.socket(); s.bind(("", 0)); print(s.getsockname()[1]); s.close()'