【发布时间】:2016-04-19 08:01:08
【问题描述】:
我这里有问题。在下面的代码中,异步/等待模式与 HttpListener 一起使用。当请求通过 HTTP 发送时,预计会出现“延迟”查询字符串参数,其值会导致服务器将上述请求处理延迟给定时间段。即使在服务器停止接收新请求后,我也需要服务器处理待处理的请求。
static void Main(string[] args)
{
HttpListener httpListener = new HttpListener();
CountdownEvent sessions = new CountdownEvent(1);
bool stopRequested = false;
httpListener.Prefixes.Add("http://+:9000/GetData/");
httpListener.Start();
Task listenerTask = Task.Run(async () =>
{
while (true)
{
try
{
var context = await httpListener.GetContextAsync();
sessions.AddCount();
Task childTask = Task.Run(async () =>
{
try
{
Console.WriteLine($"Request accepted: {context.Request.RawUrl}");
int delay = int.Parse(context.Request.QueryString["delay"]);
await Task.Delay(delay);
using (StreamWriter sw = new StreamWriter(context.Response.OutputStream, Encoding.Default, 4096, true))
{
await sw.WriteAsync("<html><body><h1>Hello world</h1></body></html>");
}
context.Response.Close();
}
finally
{
sessions.Signal();
}
});
}
catch (HttpListenerException ex)
{
if (stopRequested && ex.ErrorCode == 995)
{
break;
}
throw;
}
}
});
Console.WriteLine("Server is running. ENTER to stop...");
Console.ReadLine();
sessions.Signal();
stopRequested = true;
httpListener.Stop();
Console.WriteLine("Stopped accepting requests. Waiting for the pendings...");
listenerTask.Wait();
sessions.Wait();
Console.WriteLine("Finished");
Console.ReadLine();
httpListener.Close();
}
这里的确切问题是,当服务器停止时,会调用 HttpListener.Stop,但所有挂起的请求都会立即中止,即代码无法发回响应。
在非异步/等待模式(即简单的基于线程的实现)中,我可以选择中止线程(我认为这很糟糕),这将允许我处理挂起的请求,因为这只是中止 HttpListener.GetContext打电话。
您能否指出我做错了什么以及如何防止 HttpListener 以异步/等待模式中止挂起的请求?
【问题讨论】:
-
我的意思是我希望我的服务器停止接收新请求并能够处理待处理的请求。但是调用 HttpListener.Stop 会阻止我响应待处理的请求。至于异步/等待场景中的 CancellationToken,如果 HttpListener.GetContextAsync 根本不接受 CancellationToken,这对我有什么帮助?
-
@Luaan,顺便谢谢你,我已经更新了问题的文字和标题。
-
@Luaan,似乎是一个错误。无法强制 HttpListener 暂停接收请求并处理待处理的请求。甚至尝试过 Begin/EndGetContext 对。仍然没有运气。实际上 Thread.Abort 方法有帮助,因为它能够在不停止请求处理逻辑的情况下中止对 HttpListener.GetContext 的调用。
-
@Luaan,再次感谢。我明白你的意思。事实证明,使用 Thread.Abort 的代码隐藏了 HttpListener.GetContext 挂起的点,并且在我调用 Thread.Stop 后它立即唤醒。
-
将 cmets 移至答案 :)
标签: c# async-await abort httplistener