簡體   English   中英

如何在C#中的隨機端口上創建HttpListener類?

[英]How can I create an HttpListener class on a random port in C#?

我想創建一個在內部提供網頁的應用程序,並且可以在同一台機器上的多個實例中運行。 為此,我想創建一個偵聽端口的HttpListener

  1. 隨機選擇
  2. 目前尚未使用

基本上,我想要的是:

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偵聽器並使用該端口。 這種方法有兩個可能的問題:

  • 理論上可能會出現競爭條件,因為另一個TCP偵聽器在關閉它之后可能會使用此端口。
  • 如果您不是以管理員身份運行,則需要分配前綴和端口組合以允許綁定它。 如果您沒有管理員權限,則無法管理。 從本質上講,這將強制您需要以管理員權限運行您的HTTP服務器(這通常是一個壞主意)。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM