2012-01-27 102 views
11

我有一個.NET Windows服務,它產生一個線程,基本上只是作爲一個HttpListener。這是工作在同步模式例如精...用C#處理多個請求HttpListener

private void CreateLListener() 
{ 
    HttpListenerContext context = null; 
    HttpListener listener = new HttpListener(); 
    bool listen = true; 

    while(listen) 
    { 
     try 
     { 
      context = listener.GetContext(); 
     } 
     catch (...) 
     { 
      listen = false; 
     } 
     // process request and make response 
    } 
} 

的問題我現在是我需要這與多個請求的工作,並讓他們回答同時或至少在重疊的方式。

爲了進一步解釋 - 客戶端是媒體播放器應用程序,它開始通過讓與請求頭屬性Range bytes=0-媒體文件的請求。據我可以告訴它這是爲了弄清楚媒體容器是什麼。

它讀取了一個'chunk'(或者它已經讀取了足夠的確定媒體類型)之後,它會使用Range bytes=X-Y發出另一個請求(來自不同的客戶端套接字號)。在這種情況下,Y是第一個響應中返回的Content-Length,X比使用IIS作爲測試發現的X小250000字節。在這個階段,它會得到最後的'大塊',看看它是否可以通過媒體時間戳來衡量長度。

讀過的是,它與Range bytes=0-另一個請求(從另一個套接字號)開始正常的流媒體文件。

在任何時候,如果客戶端的用戶執行'跳過'操作,它會發送另一個請求(來自另一個套接字號)與Range bytes=Z-,其中Z是在媒體文件中跳轉到的位置。

我對HTTP的東西不太好,但據我所知,我需要使用多個線程來處理每個請求/響應,同時允許原始HttpListener返回到監聽。我已經做了大量的搜索,但找不到似乎適合的模型。

編輯:

確認和感謝里克施特拉爾以下例子我能適應適合我的需要...

Add a Web Server to your .NET 2.0 app with a few lines of code

回答

12

如果您需要更簡單的BeginGetContext替代方法,您只需將作業排列在ThreadPool中,而不是在主線程上執行它們。喜歡這樣:

private void CreateLListener() { 
    //.... 
    while(true) { 
     ThreadPool.QueueUserWorkItem(Process, listener.GetContext());  
    } 
} 
void Process(object o) { 
    var context = o as HttpListenerContext; 
    // process request and make response 
} 
+2

完美的方式來做到這一點,但掌握異步編程將更好地服務於你 – 2012-01-27 15:32:04

10

您需要使用異步方法能夠處理多個請求。所以你會使用e BeginGetContextEndGetContext方法。

看一看here

同步模型是適當的,如果您的應用程序應該阻止 在等待客戶端的請求,如果你想在同一時間只處理一個 * 要求*。使用同步模型,調用GetContext 方法,該方法等待客戶端發送請求。當發生一個HttpListenerContext對象時,該方法返回 進行處理。

+0

異步工作方式不同同步(明顯)。開始的調用會立即返回,所以您需要應對這種情況,因此大多數應用程序都有一些等待。這不會阻止。您在調用begin時指定的回調將在新線程上執行。在那裏你打電話結束,然後再開始繼續收聽,然後你做你的工作。新的請求會在新線程上處理,直到您決定停止收聽。 – 2012-01-27 15:30:29

+2

@MisterSquonk很高興它爲你工作。我們不在這裏給魚,但是教授釣魚。 :) – Aliostad 2012-01-29 13:24:41

5

如果你將來在這裏,並試圖利用異步/等待對該處理與單個線程多個併發請求..

public async Task Listen(string prefix, int maxConcurrentRequests, CancellationToken token) 
{ 
    HttpListener listener = new HttpListener(); 
    listener.Prefixes.Add(prefix); 
    listener.Start(); 

    var requests = new HashSet<Task>(); 
    for(int i=0; i < maxConcurrentRequests; i++) 
     requests.Add(listener.GetContextAsync()); 

    while (!token.IsCancellationRequested) 
    { 
     Task t = await Task.WhenAny(requests); 
     requests.Remove(t); 

     if (t is Task<HttpListenerContext>) 
     { 
      var context = (t as Task<HttpListenerContext>).Result; 
      requests.Add(ProcessRequestAsync(context)); 
      requests.Add(listener.GetContextAsync()); 
     } 
    } 
} 

public async Task ProcessRequestAsync(HttpListenerContext context) 
{ 
    ...do stuff... 
} 
+1

如果你關心來自ProcessRequestAsync的異常,並且你應該關心,不要忘記在其他分支中調用t.Wait()。總而言之,我喜歡這種方法+1。 – frast 2015-12-08 10:09:55

+0

另一個問題是while條件僅在WhenAny任務之一完成時才被檢查。 – frast 2015-12-08 10:29:57

+0

你能詳細說明爲什麼只檢查WhenAny是一個問題@frast? – LightLabyrinth 2017-03-07 15:55:58