2012-01-27 7 views
11

Ho un servizio Windows .NET che genera un thread che agisce semplicemente come HttpListener. Questo funziona bene nell'esempio modalità sincrona ...Gestione di più richieste con 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 
    } 
} 

Il problema che ora ho è ho bisogno di questo per lavorare con più richieste e li hanno risposto a simultaneamente o almeno in maniera sovrapposta.

Per spiegare ulteriormente, il client è un'app di lettore multimediale che inizia effettuando una richiesta per un file multimediale con la proprietà dell'intestazione della richiesta Range bytes=0-. Per quanto posso dire, fa questo per capire che cos'è il contenitore multimediale.

Dopo aver letto un "chunk" (o se ha letto abbastanza per accertare il tipo di supporto), effettua un'altra richiesta (da un diverso numero di socket del client) con Range bytes=X-Y. In questo caso, Y è il Content-Length restituito nella prima risposta e X è 250000 byte meno di quello (rilevato utilizzando IIS come test). A questo punto sta ottenendo l'ultimo "pezzo" per vedere se è possibile ottenere un indicatore di tempo dei media per misurare la lunghezza.

Dopo aver letto ciò, effettua un'altra richiesta con Range bytes=0- (da un altro numero di socket) per avviare correttamente lo streaming del file multimediale.

In qualsiasi momento, se l'utente del client esegue un'operazione "salta", invia un'altra richiesta (da un altro numero di socket) con Range bytes=Z- dove Z è la posizione in cui passare nel file multimediale.

Io non sono molto bravo con le cose HTTP ma, per quanto posso dire, ho bisogno di usare più thread per gestire ogni richiesta/risposta, mentre permetto al HttpListener originale di tornare all'ascolto. Ho fatto molte ricerche ma non riesco a trovare un modello che sembra adattarsi.

EDIT:

riconoscimento e gratitudine a Rick Strahl per il seguente esempio, che sono stato in grado di adattarsi per soddisfare le mie esigenze ...

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

risposta

12

Se hai bisogno di un'alternativa più semplice a BeginGetContext, puoi semplicemente mettere in coda i lavori in ThreadPool, invece di eseguirli sul thread principale.Come ad esempio:

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

Un modo perfetto per farlo, ma fare i conti con la programmazione Async renderà il server migliore –

10

È necessario utilizzare l'async metodo per essere in grado di elaborare più richieste. Quindi useresti i metodi e BeginGetContext e EndGetContext.

Dai uno sguardo allo here.

Il modello sincrono è appropriata se l'applicazione deve bloccare in attesa di una richiesta del client e se si desidera elaborare solo uno * richiesta alla volta *. Utilizzando il modello sincrono, chiamare il metodo GetContext , che attende che un client invii una richiesta. Il metodo restituisce un oggetto HttpListenerContext per l'elaborazione quando si verifica uno.

+0

asincrona funziona in modo diverso per la sincronizzazione (ovviamente). La chiamata per iniziare verrà immediatamente restituita, quindi è necessario farvi fronte, quindi la maggior parte delle app ha una sorta di waitone. Questo però non bloccherà. Il callback specificato al momento della chiamata begin verrà eseguito su un nuovo thread. Dentro lì chiami fine seguito da ricomincia per continuare ad ascoltare e poi fai il tuo lavoro. nuove richieste vengono gestite su nuovi thread fino a quando non si decide di interrompere l'ascolto. –

+2

@MisterSquonk è contento che abbia funzionato per te. Non diamo pesci qui, ma insegniamo a pescare. :) – Aliostad

5

Se siete qui dal futuro e cercando di gestire più richieste simultanee con un singolo thread utilizzando asincrona/await ..

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

Se ti interessano le eccezioni da ProcessRequestAsync e dovresti preoccuparti, non dimenticare di chiamare t.Wait() in un altro ramo. Tutto sommato mi piace questo approccio +1. – frast

+0

Un altro problema è che la condizione while viene controllata solo se una delle attività WhenAny è completa. – frast

+0

puoi approfondire perché solo il controllo su WhenAny è un problema @frast? – LightLabyrinth