首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何防止HttpListener在停止时中止挂起的请求?HttpListener.Stop不起作用

如何防止HttpListener在停止时中止挂起的请求?HttpListener.Stop不起作用
EN

Stack Overflow用户
提问于 2016-04-19 08:01:08
回答 1查看 3.2K关注 0票数 1

我这里有个问题。在下面的代码中,异步/等待模式与HttpListener一起使用。当通过HTTP“延迟”查询字符串参数发送请求时,它的值将导致服务器将上述请求处理延迟给定时间。我需要服务器处理挂起的请求,即使服务器停止接收新的请求。

代码语言:javascript
复制
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在异步/等待模式中中止挂起的请求?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2016-04-20 08:04:47

HttpListener关闭请求队列句柄时,正在进行的请求似乎被中止。据我所知,没有办法避免让HttpListener这样做-显然,这是一个兼容性的问题。无论如何,它的GetContext-ending系统就是这样工作的--当句柄关闭时,用于实际获取请求上下文的本机方法GetContext调用将立即返回一个错误。

Thread.Abort没有帮助--实际上,我还没有看到在“应用程序域卸载”场景之外正确使用Thread.Abort的地方。Thread.Abort只能中止托管代码。由于您的代码当前正在运行本机,所以只有当它返回到托管代码时才会中止--这几乎完全等同于执行以下操作:

代码语言:javascript
复制
var context = await httpListener.GetContextAsync();

if (stopRequested) return;

..。而且,由于没有更好的HttpListener取消API,如果您想坚持使用HttpListener,这确实是您唯一的选择。

关机将如下所示:

代码语言:javascript
复制
stopRequested = true;
sessions.Wait();

httpListener.Dispose();
listenerTask.Wait();

我还建议使用CancellationToken而不是bool标志-它为您处理所有同步问题。如果出于某种原因这是不可取的,请确保您以契约的方式同步对标志的访问,允许编译器省略检查,因为标记不可能在单线程代码中更改。

如果您愿意,您可以在设置listenerTask后立即发送一个虚拟HTTP请求,从而使stopRequested更快地完成--这将导致GetContext立即与新请求一起返回,并且您可以返回。这是一种在处理不支持“很好”取消的API时常用的方法,例如UdpClient.Receive

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/36712136

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档