6

I have implemented an asynchronous http listener in c#.

I followed the tutorial provided here by Microsoft

and found another tutorial which i stupidly not bookmarked and now can't find again. Meaning that I have some code that I would not have written that way myself but the explanations provided made sense so I followed that.

Now I am facing two problems:

First, I have to restart the listener after each request with Listener.Stop() and then call the StartListening method and again and second, when I do this, I receive each request twice. The request does net get sent twice, but I receive it twice. It does not however get received twice when I pause the Thread I am listening on for about 2 seconds.

I am sorry if I am quite vague in my explanations, but so is my understanding of my problem, I have no idea what is causing it. Since the callback method is where most of the stuff happens, I will just post it, please tell me if you need any more code. Any help will be gladly appreciated, since I am really stuck on this one.

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) { } } 
3
  • Without knowing what invokes this callback, how WaitHandle listenForNextRequest is used and what method ListenAsynchronously does, it's a bit of a guessing game. Commented May 5, 2011 at 9:06
  • Sorry for that, I added the code Commented May 5, 2011 at 10:01
  • you should print out to console (or log to file, if you prefer) some useful debug information and post here. Please specify what OS you use to run this code and its version. In this way will be more simple trying to help you... Regards, Giacomo Commented Nov 10, 2011 at 6:39

1 Answer 1

6

I am not sure why you are calling StopListening() and ListenAsynchronously() in your ListenerCallback() method. The Listen() method is being run in a thread and will continue to get each next incoming request. If I was writing this, I would not be using a instance variable of HttpListener. Create a new one in your ListenAsynchronously method and pass it in your state object, for example,

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) { } } } 
Sign up to request clarification or add additional context in comments.

1 Comment

I used this as the base for serving simple pages out of a .Net 2.0 app and I'm very impressed with how well it works. On my laptop I'm able to serve around 130-200 requests per second to a simple single threaded load test script and around 20 requests per second to each of 5 instances of that test script simultaneously. The server code used about 12% of my CPU during those tests.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.