Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it possible to call HttpListener.GetContext with a timeout?

According to the HttpListener reference, a call to HttpListener.GetContext will block until it gets a HTTP request from a client.

I wonder if I can specify a timeout so that after the timeout the function will return. I think otherwise it's unreasonable, since you cannot garantee there will be a request to make this function return, then how can one terminate this call?

P.S. I know there is a async version of it (BeginGetContext) BUT the problem remains because the corresponding EndGetContext will block until an HTTP request arrives.

So as a result, there will be always one thread (if you do it multi-threaded) cannot return because it's blocked on waiting for a request.

Am I missing anything?

UPDATE:

I found this link to be useful. I also found that calling HttpListener.Close() actually terminates the waiting threads that created by the BeginGetContext()s. Somehow HttpListener.Close() fires the callbacks that BeginGetContext() registered. So before you do a HttpListener.EndGetContext(), do check if HttpListener has stopped.

like image 889
KFL Avatar asked Feb 08 '12 05:02

KFL


2 Answers

Also if you want to do line by line in process handling waiting for a limited time the BeginGetContext returns a System.IAsyncResult exposing the AsyncWaitHandle property

var context = listener.BeginGetContext(new AsyncCallback(ListenerCallback), listener);
context.AsyncWaitHandle.WaitOne();

Above blocks the thread until the listener receives something valid as defined by the heders assigned to the listener or terminates due to some exception that terminates the listener thread and returns result back to ListenerCallback.

But the AsyncWaitHandle.WaitOne() can take timeout parameters

// 5 seconds timeout
bool success = context.AsyncWaitHandle.WaitOne(5000, true);

if (success == false)
{
    throw new Exception("Timeout waiting for http request.");
}

The ListenerCallback could contain a call to listener.EndGetContext or just call the listener.EndGetContext in line if no timeout or error indicated by the AsyncWaitHandle

public static void ListenerCallback(IAsyncResult result)
{
    HttpListener listener = (HttpListener) result.AsyncState;
    // Use EndGetContext to complete the asynchronous operation.
    HttpListenerContext context = listener.EndGetContext(result);
    HttpListenerRequest request = context.Request;
    // Get response object.
    HttpListenerResponse response = context.Response;
    // Construct a response. 
    string responseString = "<HTML><BODY> It Works!</BODY></HTML>";
    byte[] buffer = System.Text.Encoding.UTF8.GetBytes(responseString);
    // Write to response stream.
    response.ContentLength64 = buffer.Length;
    System.IO.Stream output = response.OutputStream;
    output.Write(buffer,0,buffer.Length);
    // Close the output stream.
    output.Close();
}

Not to forget to tell the listener to listen again using listener.BeginGetContext

like image 102
tofo Avatar answered Oct 26 '22 04:10

tofo


The callback that invokes EndGetContext should never be called unless an HTTP request has already arrived, or the listener has failed (in which case EndGetContext will throw an exception). Thus, it will not block if used properly.

BeginGetContext and EndGetContext--that is, asynchronous operations--are what you want.

Begin and End methods work such that Begin says "signal me when X is ready," and End says "give me that X about which you just signaled me." Naturally, the latter will block in theory, but will return instantaneously.

like image 36
Zenexer Avatar answered Oct 26 '22 04:10

Zenexer