[英]How can I create an HttpListener class on a random port in C#?
我想創建一個在內部提供網頁的應用程序,並且可以在同一台機器上的多個實例中運行。 為此,我想創建一個偵聽端口的HttpListener
:
基本上,我想要的是:
mListener = new HttpListener();
mListener.Prefixes.Add("http://*:0/");
mListener.Start();
selectedPort = mListener.Port;
我怎么能做到這一點?
如果綁定到端口0,TcpListener將找到一個隨機未使用的端口來偵聽。
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;
}
我不確定你將如何找到該機器上正在使用的所有端口,但如果你試圖監聽已經使用的端口,你應該得到一個例外,在這種情況下,該方法只會選擇另一個港口。
這是一個答案,源自Snooganz的答案 。 它避免了測試可用性和后期綁定之間的競爭條件。
public 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;
}
在我的機器上,這種方法平均需要15毫秒,這對我的用例是可以接受的。 希望這有助於其他人。
由於您使用的是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
。
另外請記住,在您執行之前某些其他進程占用找到的端口時可能會發生競爭條件。
我建議嘗試Grapevine 。 它允許您在應用程序中嵌入REST / HTTP服務器。 它包含一個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/en-us/library/system.uribuilder.port(v=vs.110).aspx
不幸的是,這是不可能的。 正如Richard Dingwall已經建議的那樣,您可以創建一個TCP偵聽器並使用該端口。 這種方法有兩個可能的問題:
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.