2012-01-27 25 views
11

que tienen un servicio de Windows .NET, que genera un subproceso que básicamente actúa como un HttpListener. Esto funciona bien en el ejemplo el modo sincrónico ...manejar múltiples peticiones 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 
    } 
} 

El problema que ahora tengo es que necesito que esto funcione con múltiples peticiones y hacer que respondieron al mismo tiempo o al menos de una manera solapada.

Explicando más: el cliente es una aplicación de reproductor multimedia que comienza solicitando un archivo multimedia con la propiedad de encabezado de solicitud Range bytes=0-. Hasta donde sé, hace esto para determinar qué es el contenedor de medios.

Después de leer un "fragmento" (o si ha leído lo suficiente como para determinar el tipo de medio), realiza otra solicitud (desde un número de socket de cliente diferente) con Range bytes=X-Y. En este caso, Y es la longitud del contenido devuelta en la primera respuesta y X tiene 250000 bytes menos que (descubierta utilizando IIS como prueba). En esta etapa, está obteniendo el último "trozo" para ver si puede obtener un sello de tiempo de los medios para medir la longitud.

Después de leer eso, se hace otra petición con Range bytes=0- (de otro número de socket) para iniciar la transmisión del archivo multimedia correctamente.

En cualquier momento, si el usuario del cliente realiza una operación de "omisión" envía otra solicitud (desde otro número de socket) con Range bytes=Z- donde Z es la posición para saltar en el archivo multimedia.

No soy muy bueno con las cosas de HTTP pero, por lo que puedo decir, necesito usar múltiples hilos para manejar cada solicitud/respuesta mientras que el original HttpListener vuelve a escuchar. He hecho muchas búsquedas pero no puedo encontrar un modelo que parezca encajar.

EDIT:

Reconocimiento y agradecimiento a Rick Strahl para el siguiente ejemplo que yo era capaz de adaptarse para satisfacer mis necesidades ...

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

Respuesta

12

Si necesita una alternativa más simple a BeginGetContext, puede simplemente cola de trabajos en ThreadPool, en lugar de ejecutarlos en el hilo principal.Como por ejemplo:

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

Perfectamente buena manera de hacerlo, pero al hacer uso de la programación Async le servirá mejor –

10

Es necesario utilizar el asíncrono método para poder procesar solicitudes múltiples. Entonces usaría los métodos e BeginGetContext y EndGetContext.

Tener una mirada here.

El modelo síncrono es apropiado si su aplicación debe bloquear a la espera de una petición del cliente y si desea procesar sólo uno * solicitud a la vez *. Con el modelo síncrono, llame al método GetContext , que espera que un cliente envíe una solicitud. El método devuelve un objeto HttpListenerContext para su procesamiento cuando se produce uno.

+0

asíncrono funciona de forma diferente a sincronizar (obviamente). La llamada para comenzar regresará de inmediato, por lo que debes lidiar con eso, por lo tanto, la mayoría de las aplicaciones tienen algún tipo de waitone. Eso no se bloqueará sin embargo. La devolución de llamada que especificó cuando llamó a begin se ejecutará en un nuevo hilo. Dentro de allí llamas al final seguido de comenzar de nuevo para seguir escuchando y luego haces tu trabajo. las nuevas solicitudes se manejan en nuevos hilos hasta que decida dejar de escuchar. –

+2

@MisterSquonk satisfecho de que funcionó para usted. Aquí no damos peces, sino que enseñamos a pescar. :) – Aliostad

5

Si estás aquí desde el futuro y tratando de manejar múltiples solicitudes simultáneas con un solo hilo usando asíncrono/aguarde ..

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

Si le importan las Excepciones de ProcessRequestAsync, y le debe importar, no olvide llamar a t.Wait() en una rama else. En general, me gusta este enfoque +1. – frast

+0

Otro problema es que la condición while solo se verifica si se completa una de las tareas WhenAny. – frast

+0

¿Puede explicar por qué solo consultar en WhenAny es un problema @frast? – LightLabyrinth

Cuestiones relacionadas