2012-06-23 104 views
21

這將是一個可擴展的HttpListener一個很好的例子是多線程?多線程HttpListener與等待異步和任務

請問這是怎麼例如一個真正的IIS會做呢?

public class Program 
{ 
    private static readonly HttpListener Listener = new HttpListener(); 

    public static void Main() 
    { 
     Listener.Prefixes.Add("http://+:80/"); 
     Listener.Start(); 
     Listen(); 
     Console.WriteLine("Listening..."); 
     Console.WriteLine("Press any key to exit..."); 
     Console.ReadKey(); 
    } 

    private static async void Listen() 
    { 
     while (true) 
     { 
      var context = await Listener.GetContextAsync(); 
      Console.WriteLine("Client connected"); 
      Task.Factory.StartNew(() => ProcessRequest(context)); 
     } 

     Listener.Close(); 
    } 

    private static void ProcessRequest(HttpListenerContext context) 
    { 
     System.Threading.Thread.Sleep(10*1000); 
     Console.WriteLine("Response"); 
    } 
} 

我專門找不依賴於IIS的可擴展解決方案。取而代之的只是http.sys(這是httplistener類) - 不依賴iIS的原因是因爲政府。我工作的地區需要極大地減少攻擊面積。

回答

19

我已經做了在https://github.com/JamesDunne/Aardwolf類似的東西,也做了一些這方面的廣泛的測試。

看到https://github.com/JamesDunne/aardwolf/blob/master/Aardwolf/HttpAsyncHost.cs#L107爲核心事件循環的實現代碼。

我發現使用Semaphore來控制有多少併發的GetContextAsync請求是最好的方法。實際上,主循環會繼續運行,直到信號因計數達到而阻塞線程。然後會有N個併發的「連接接受」活動。每次連接被接受時,信號量都會被釋放,並且新的請求可以取代它。

信號燈的初始和最大計數值需要進行一些微調,這取決於你期望得到的負荷。這是您期望的併發連接數量與客戶期望的平均響應時間之間的微妙平衡。更高的值意味着更多的連接可以在平均響應時間慢得多的情況下保持;更少的連接將被拒絕。數值越低意味着連接的維持時間越短,但平均響應時間要快得多;更多的連接將被拒絕。

我發現,通過實驗(在我的硬件上),大約128的值允許服務器在可接受的響應時間處理大量的併發連接(高達1,024)。使用您自己的硬件進行測試並相應地調整您的參數。

我也發現WCAT的單個實例不喜歡自己處理超過1,024個連接。因此,如果您對負載測試非常認真,請使用WCAT對您的服務器的多臺客戶端計算機,並確保通過快速網絡進行測試,例如10 GbE,並且您的操作系統的限制不會讓您失望。請務必在Windows Server SKU上進行測試,因爲桌面SKU默認情況下受限。

摘要: 你怎麼寫你的連接接受循環是你的服務器的可擴展性是至關重要的。

+0

鏈接已死... –

+0

更新的鏈接。感謝您的評論! –

+0

使用信號量和ServicePointManager.DefaultConnectionLimit是否有區別? –

5

從技術上講,你是對的。爲了使其具有可伸縮性,您可能希望同時運行多個GetContextAsync(性能測試需要確切知道有多少個,但「每個內核少數幾個」可能是正確的答案)。

那麼自然,正如評論中指出,不使用IIS意味着您需要非常認真對待IIS爲您提供的許多「免費」安全性。