根据 HttpListener 参考,对 HttpListener.GetContext 的调用将被阻塞,直到它从客户端获取 HTTP 请求。
我想知道是否可以指定一个超时,以便在超时后函数将返回。我认为否则这是不合理的,因为你不能保证会有一个请求让这个函数返回,那么如何终止这个调用呢?
附注我知道它有一个异步版本(BeginGetContext),但问题仍然存在,因为相应的 EndGetContext 将阻塞,直到 HTTP 请求到达。
因此,总会有一个线程(如果您使用多线程)无法返回,因为它在等待请求时被阻塞。
我错过了什么吗?
更新:
我发现此链接很有用。我还发现调用 HttpListener.Close() 实际上终止了 BeginGetContext() 创建的等待线程。不知何故 HttpListener.Close() 会触发 BeginGetContext() 注册的回调。因此,在执行 HttpListener.EndGetContext() 之前,请检查 HttpListener 是否已停止。
此外,如果您想在等待有限时间的进程处理中逐行执行,则 BeginGetContext 返回暴露 AsyncWaitHandle 属性的 System.IAsyncResult
var context = listener.BeginGetContext(new AsyncCallback(ListenerCallback), listener);
context.AsyncWaitHandle.WaitOne();
上面会阻塞线程,直到侦听器收到分配给侦听器的 heder 定义的有效内容,或者由于某些异常而终止侦听器线程并将结果返回给 ListenerCallback。
但是AsyncWaitHandle.WaitOne()可以带超时参数
// 5 seconds timeout
bool success = context.AsyncWaitHandle.WaitOne(5000, true);
if (success == false)
{
throw new Exception("Timeout waiting for http request.");
}
ListenerCallback 可以包含对listener.EndGetContext 的调用,或者如果AsyncWaitHandle 没有指示超时或错误,则仅调用listener.EndGetContext
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();
}
不要忘记告诉监听者使用listener.BeginGetContext再次监听
永远不应该调用调用 EndGetContext 的回调,除非 HTTP 请求已经到达,或者侦听器失败(在这种情况下 EndGetContext 将抛出异常)。因此,如果使用得当,它不会阻塞。
BeginGetContext 和 EndGetContext——即异步操作——就是你想要的。
Begin 和 End 方法的工作原理是,Begin 说“当 X 准备好时向我发出信号”,End 说“将您刚刚向我发出信号的 X 给我”。当然,后者理论上会阻塞,但会瞬间返回。