我希望创建一个应用程序,可以在同一台计算机上的多个实例中提供内部网页服务。为此,我想创建一个HttpListener
,它监听随机选择且当前未使用的端口。
总体来说,我想要的是:
mListener = new HttpListener();
mListener.Prefixes.Add("http://*:0/");
mListener.Start();
selectedPort = mListener.Port;
我该如何完成这个任务?
我希望创建一个应用程序,可以在同一台计算机上的多个实例中提供内部网页服务。为此,我想创建一个HttpListener
,它监听随机选择且当前未使用的端口。
总体来说,我想要的是:
mListener = new HttpListener();
mListener.Prefixes.Add("http://*:0/");
mListener.Start();
selectedPort = mListener.Port;
我该如何完成这个任务?
如果你将TcpListener绑定到端口0,则它会找到一个随机未使用的端口进行监听。
public static int GetRandomUnusedPort()
{
var listener = new TcpListener(IPAddress.Any, 0);
listener.Start();
var port = ((IPEndPoint)listener.LocalEndpoint).Port;
listener.Stop();
return port;
}
这个怎么样:
static List<int> usedPorts = new List<int>();
static Random r = new Random();
public HttpListener CreateNewListener()
{
HttpListener mListener;
int newPort = -1;
while (true)
{
mListener = new HttpListener();
newPort = r.Next(49152, 65535); // IANA suggests the range 49152 to 65535 for dynamic or private ports.
if (usedPorts.Contains(newPort))
{
continue;
}
mListener.Prefixes.Add(string.Format("http://*:{0}/", newPort));
try
{
mListener.Start();
}
catch
{
continue;
}
usedPorts.Add(newPort);
break;
}
return mListener;
}
我不确定您如何找到该计算机上正在使用的所有端口,但如果您尝试在已被使用的端口上进行侦听,则应该会收到异常,在这种情况下,该方法将简单地选择另一个端口。
MinPort
常量的值为零。答案中给出的最小值更加合适。 - Drew NoakesmListener
。此外,usedPorts
应该是一个Set<int>
,以进行线性成员测试。个人建议在方法内部限定usedPorts
的作用域(或者干脆将其删除),因为如果您在一个非常长时间运行的系统中使用它,最终可能会用尽端口,使得while
循环永远运行,即使随着时间的推移可用端口变多。 - Drew Noakespublic static bool TryBindListenerOnFreePort(out HttpListener httpListener, out int port)
{
// IANA suggested range for dynamic or private ports
const int MinPort = 49215;
const int MaxPort = 65535;
for (port = MinPort; port < MaxPort; port++)
{
httpListener = new HttpListener();
httpListener.Prefixes.Add($"http://localhost:{port}/");
try
{
httpListener.Start();
return true;
}
catch
{
// nothing to do here -- the listener disposes itself when Start throws
}
}
port = 0;
httpListener = null;
return false;
}
由于您正在使用HttpListener(因此使用TCP连接),因此可以使用IPGlobalProperties
对象的GetActiveTcpListeners
方法获取活动TCP侦听器列表,并检查其Port
属性。
可能的解决方案如下:
private static bool TryGetUnusedPort(int startingPort, ref int port)
{
var listeners = IPGlobalProperties.GetIPGlobalProperties().GetActiveTcpListeners();
for (var i = startingPort; i <= 65535; i++)
{
if (listeners.Any(x => x.Port == i)) continue;
port = i;
return true;
}
return false;
}
这段代码将从startingPort
端口号开始查找第一个未使用的端口,并返回true
。如果所有端口都已被占用(这是非常不可能的),则该方法返回false
。
还要注意可能发生的竞争条件,即在您之前其他进程占用了找到的端口。
out
而是使用ref
? - Drew Noakesref
。 - dodbrian很遗憾,这是不可能的。正如Richard Dingwall所建议的那样,您可以创建一个TCP监听器并使用该端口。这种方法有两个可能的问题:
RestCluster
类,可以让您在单个位置管理所有 RestServer
实例。using (var server = new RestServer())
{
// Grab the next open port (starts at 1)
server.Port = PortFinder.FindNextLocalOpenPort();
// Grab the next open port after 2000 (inclusive)
server.Port = PortFinder.FindNextLocalOpenPort(2000);
// Grab the next open port between 2000 and 5000 (inclusive)
server.Port = PortFinder.FindNextLocalOpenPort(200, 5000);
...
}
入门指南:https://sukona.github.io/Grapevine/en/getting-started.html
我不相信这是可能的。UriBuilder.Port 的文档说明:“如果端口没有作为 URI 的一部分指定,...则协议方案的默认端口值将用于连接到主机。”。
请参见 https://msdn.microsoft.com/zh-cn/library/system.uribuilder.port(v=vs.110).aspx