2011-05-05 13 views
5

He implementado un oyente http asincrónico en C#.HttpListener asíncrono tiene cada solicitud se recibe dos veces

he seguido el tutorial proporciona here by Microsoft

y encontró otro tutorial que me estúpidamente no bookmarked y ahora no puede encontrar de nuevo. Lo que significa que tengo un código que yo no habría escrito de esa manera pero las explicaciones proporcionadas tenían sentido, así que seguí eso.

Ahora estoy frente a dos problemas:

En primer lugar, tengo que reiniciar el oyente después de cada petición con Listener.Stop() y luego llamar al método StartListening y otra vez y en segundo lugar, cuando hago esto, recibo cada solicitud dos veces. La solicitud no se envía netamente dos veces, pero la recibo dos veces. Sin embargo, no se recibe dos veces cuando pongo en pausa el hilo que estoy escuchando durante unos 2 segundos.

Lo siento si soy bastante vago en mis explicaciones, pero también lo es mi comprensión de mi problema, no tengo idea de qué lo está causando. Dado que el método de devolución de llamada es donde ocurre la mayoría de las cosas, solo lo publicaré, por favor dígame si necesita más código. Cualquier ayuda será gratamente apreciada, ya que estoy realmente atrapado en esta.

public void ListenAsynchronously() 
    { 

     if (listener.Prefixes.Count == 0) foreach (string s in prefixes) listener.Prefixes.Add(s); 

     try 
     { 
      listener.Start(); 
     } 
     catch (Exception e) 
     { 
      Logging.logException(e); 
     } 

     System.Threading.ThreadPool.QueueUserWorkItem(new System.Threading.WaitCallback(Listen)); 
    } 


    private void Listen(object state) 
    { 
     while (listener.IsListening) 
     { 
      listener.BeginGetContext(new AsyncCallback(ListenerCallback), listener); 
      listenForNextRequest.WaitOne(); 
     } 
    } 
    private void ListenerCallback(IAsyncResult ar) 
    { 

     HttpListener httplistener = ar.AsyncState as System.Net.HttpListener; 
     System.Net.HttpListenerContext context = null; 

     int requestNumber = System.Threading.Interlocked.Increment(ref requestCounter); 

     if (httplistener == null) return; 

     try 
     { 
      context = httplistener.EndGetContext(ar); 
     } 
     catch(Exception ex) 
     { 
      return; 
     } 
     finally 
     { 
      listenForNextRequest.Set(); 
     } 

     if (context == null) return; 


     System.Net.HttpListenerRequest request = context.Request; 

     if (request.HasEntityBody) 
     { 
      using (System.IO.StreamReader sr = new System.IO.StreamReader(request.InputStream, request.ContentEncoding)) 
      { 
       string requestData = sr.ReadToEnd(); 

       //Stuff I do with the request happens here 

      } 
     } 


     try 
     { 
      using (System.Net.HttpListenerResponse response = context.Response) 
      { 
       //response stuff happens here 

       } 

       byte[] buffer = System.Text.Encoding.UTF8.GetBytes(responseString); 
       response.ContentLength64 = buffer.LongLength; 
       response.OutputStream.Write(buffer, 0, buffer.Length); 
       response.Close(); 


       StopListening(); 
       //If I dont set the thread to sleep here, I receive the double requests 
       System.Threading.Thread.Sleep(2500); 

       ListenAsynchronously(); 


      } 
     } 
     catch (Exception e) 
     { 
     } 

    } 
+0

Sin saber lo que invoca esta devolución de llamada, cómo se utiliza WaitHandle listenForNextRequest y qué método hace ListenAsynchronously, que es un poco de un juego de adivinanzas . – spender

+0

Disculpe por eso, agregué el código – Daniel

+0

que debe imprimir en la consola (o registrar en el archivo, si lo prefiere) alguna información de depuración útil y publicar aquí. Especifique qué sistema operativo usa para ejecutar este código y su versión. De esta forma será más sencillo intentar ayudarte ... Saludos, Giacomo – gsscoder

Respuesta

6

No estoy seguro de por qué está llamando StopListening() y ListenAsynchronously() en su método ListenerCallback(). El método Listen() se está ejecutando en un subproceso y continuará recibiendo cada próxima solicitud entrante. Si estuviera escribiendo esto, no estaría usando una variable de instancia de HttpListener. Crear una nueva en su método de ListenAsynchronously y pasarlo en su objeto de estado, por ejemplo,

public class HttpListenerCallbackState 
{ 
    private readonly HttpListener _listener; 
    private readonly AutoResetEvent _listenForNextRequest; 

    public HttpListenerCallbackState(HttpListener listener) 
    { 
     if (listener == null) throw new ArgumentNullException("listener"); 
     _listener = listener; 
     _listenForNextRequest = new AutoResetEvent(false); 
    } 

    public HttpListener Listener { get { return _listener; } } 
    public AutoResetEvent ListenForNextRequest { get { return _listenForNextRequest; } } 
} 

public class HttpRequestHandler 
{ 
    private int requestCounter = 0; 
    private ManualResetEvent stopEvent = new ManualResetEvent(false); 

    public void ListenAsynchronously(IEnumerable<string> prefixes) 
    { 
     HttpListener listener = new HttpListener(); 

     foreach (string s in prefixes) 
     { 
      listener.Prefixes.Add(s); 
     } 

     listener.Start(); 
     HttpListenerCallbackState state = new HttpListenerCallbackState(listener); 
     ThreadPool.QueueUserWorkItem(Listen, state); 
    } 

    public void StopListening() 
    { 
     stopEvent.Set(); 
    } 


    private void Listen(object state) 
    { 
     HttpListenerCallbackState callbackState = (HttpListenerCallbackState)state; 

     while (callbackState.Listener.IsListening) 
     { 
      callbackState.Listener.BeginGetContext(new AsyncCallback(ListenerCallback), callbackState); 
      int n = WaitHandle.WaitAny(new WaitHandle[] { callbackState.ListenForNextRequest, stopEvent}); 

      if (n == 1) 
      { 
       // stopEvent was signalled 
       callbackState.Listener.Stop(); 
       break; 
      } 
     } 
    } 

    private void ListenerCallback(IAsyncResult ar) 
    { 
     HttpListenerCallbackState callbackState = (HttpListenerCallbackState)ar.AsyncState; 
     HttpListenerContext context = null; 

     int requestNumber = Interlocked.Increment(ref requestCounter); 

     try 
     { 
      context = callbackState.Listener.EndGetContext(ar); 
     } 
     catch (Exception ex) 
     { 
      return; 
     } 
     finally 
     { 
      callbackState.ListenForNextRequest.Set(); 
     } 

     if (context == null) return; 


     HttpListenerRequest request = context.Request; 

     if (request.HasEntityBody) 
     { 
      using (System.IO.StreamReader sr = new System.IO.StreamReader(request.InputStream, request.ContentEncoding)) 
      { 
       string requestData = sr.ReadToEnd(); 

       //Stuff I do with the request happens here 
      } 
     } 


     try 
     { 
      using (HttpListenerResponse response = context.Response) 
      { 
       //response stuff happens here 
       string responseString = "Ok"; 

       byte[] buffer = Encoding.UTF8.GetBytes(responseString); 
       response.ContentLength64 = buffer.LongLength; 
       response.OutputStream.Write(buffer, 0, buffer.Length); 
       response.Close(); 
      } 
     } 
     catch (Exception e) 
     { 
     } 
    } 
} 
+1

Lo usé como base para publicar páginas simples desde una aplicación .Net 2.0 y estoy muy impresionado con lo bien que funciona. En mi computadora portátil, puedo atender alrededor de 130-200 solicitudes por segundo a un simple script de prueba de carga de un solo hilo y alrededor de 20 solicitudes por segundo a cada una de las 5 instancias de ese script de prueba simultáneamente. El código del servidor usó aproximadamente el 12% de mi CPU durante esas pruebas. –

Cuestiones relacionadas