2011-05-05 24 views
5

Tôi đã triển khai trình nghe http không đồng bộ trong C#.HttpListener không đồng bộ có mỗi yêu cầu được nhận hai lần

Tôi làm theo các hướng dẫn được cung cấp here by Microsoft

và tìm thấy một hướng dẫn mà tôi ngớ ngẩn không đánh dấu và bây giờ không thể tìm lại. Có nghĩa là tôi có một số mã mà tôi sẽ không viết theo cách đó nhưng những lời giải thích được cung cấp có ý nghĩa nên tôi đã theo dõi điều đó.

Bây giờ tôi đang phải đối mặt với hai vấn đề:

Trước tiên, tôi phải khởi động lại nghe sau mỗi lần yêu cầu với Listener.Stop() và sau đó gọi phương thức StartListening và một lần nữa và lần thứ hai, khi tôi làm điều này, tôi nhận được mỗi yêu cầu hai lần. Yêu cầu gửi net được gửi hai lần, nhưng tôi nhận được hai lần. Tuy nhiên, nó không nhận được hai lần khi tôi tạm dừng Chủ đề mà tôi đang nghe trong khoảng 2 giây.

Tôi xin lỗi nếu tôi khá mơ hồ trong các giải thích của mình, nhưng vì vậy sự hiểu biết của tôi về vấn đề của tôi, tôi không biết điều gì đang gây ra nó. Vì phương thức gọi lại là nơi mà hầu hết mọi thứ xảy ra, tôi sẽ chỉ đăng nó, hãy cho tôi biết nếu bạn cần thêm bất kỳ mã nào. Bất kỳ sự trợ giúp nào cũng sẽ được đánh giá cao, vì tôi thực sự bị mắc kẹt trong vấn đề này.

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

Mà không biết những gì gọi callback này, làm thế nào WaitHandle listenForNextRequest được sử dụng và những gì phương pháp ListenAsynchronously có, đó là một chút của một trò chơi đoán . – spender

+0

Xin lỗi vì điều đó, tôi đã thêm mã – Daniel

+0

bạn nên in ra bảng điều khiển (hoặc đăng nhập vào tệp, nếu bạn thích) một số thông tin gỡ lỗi hữu ích và đăng tại đây. Vui lòng chỉ định hệ điều hành bạn sử dụng để chạy mã này và phiên bản của hệ điều hành. Bằng cách này sẽ đơn giản hơn để cố gắng giúp bạn ... Trân trọng, Giacomo – gsscoder

Trả lời

6

Tôi không chắc chắn lý do tại sao bạn đang gọi StopListening()ListenAsynchronously() trong phương pháp ListenerCallback() của bạn. Phương thức Listen() đang được chạy trong một chuỗi và sẽ tiếp tục nhận được mỗi yêu cầu đến tiếp theo. Nếu tôi đã viết này, tôi sẽ không được sử dụng một biến thể hiện của HttpListener. Tạo một hình mới trong phương pháp ListenAsynchronously của bạn và vượt qua nó trong đối tượng trạng thái của bạn, ví dụ,

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

Tôi đã sử dụng cơ sở này để phục vụ các trang đơn giản trong ứng dụng .Net 2.0 và tôi rất ấn tượng với cách hoạt động của nó. Trên máy tính xách tay của tôi, tôi có thể phục vụ khoảng 130-200 yêu cầu mỗi giây cho một kịch bản thử nghiệm tải đơn luồng đơn giản và khoảng 20 yêu cầu mỗi giây cho mỗi 5 phiên bản của tập lệnh thử nghiệm đó cùng một lúc. Mã máy chủ sử dụng khoảng 12% CPU của tôi trong các thử nghiệm đó. –

Các vấn đề liên quan