.net - 异步使用的 HttpListener 同步运行

标签 .net http .net-4.5 windows-server-2012-r2

我正在使用 System.Net.HttpListener BeginGetContext/EndGetContext 来同时处理多个 http 请求。这在我的 16 核 Windows 7 SP1 桌面上运行良好,它同时处理 16 个请求。在 Windows Server 2012 R2 16 处理器 VM 上,20 个请求中的前 2 个是并发处理的,然后是顺序处理的请求,例如第三个请求的响应必须在查看第四个请求的请求之前发送。

我希望服务器以类似于桌面 m/c 的方式处理请求。在 8 秒内处理 20 个请求,而不是当前的 95 秒。

以下日志显示了 Windows 7 机器上的行为(良好)。客户端和服务器进程都在 Windows 7 m/c 上运行。

这是客户端日志。每行包含客户端的原始请求,服务器回显并加上服务器处理请求的时间。原始请求包含序列号和客户端发出请求的时间。

请注意,所有请求均在整点 12:46 分发出,16 点在 12:51 得到响应,最后一个在 12:54 得到响应。

http://localhost:8894/dostuff?val=1-client-12:46-server-12:51
http://localhost:8894/dostuff?val=17-client-12:46-server-12:51
http://localhost:8894/dostuff?val=15-client-12:46-server-12:51
http://localhost:8894/dostuff?val=2-client-12:46-server-12:51
http://localhost:8894/dostuff?val=7-client-12:46-server-12:51
http://localhost:8894/dostuff?val=3-client-12:46-server-12:51
http://localhost:8894/dostuff?val=13-client-12:46-server-12:51
http://localhost:8894/dostuff?val=18-client-12:46-server-12:51
http://localhost:8894/dostuff?val=9-client-12:46-server-12:51
http://localhost:8894/dostuff?val=14-client-12:46-server-12:51
http://localhost:8894/dostuff?val=0-client-12:46-server-12:51
http://localhost:8894/dostuff?val=6-client-12:46-server-12:51
http://localhost:8894/dostuff?val=10-client-12:46-server-12:51
http://localhost:8894/dostuff?val=5-client-12:46-server-12:51
http://localhost:8894/dostuff?val=19-client-12:46-server-12:51
http://localhost:8894/dostuff?val=11-client-12:46-server-12:51
http://localhost:8894/dostuff?val=12-client-12:46-server-12:52
http://localhost:8894/dostuff?val=16-client-12:46-server-12:53
http://localhost:8894/dostuff?val=8-client-12:46-server-12:53
http://localhost:8894/dostuff?val=4-client-12:46-server-12:54

以下日志显示了 Windows Server 2012 计算机上的行为(错误)。客户端和服务器进程都在 Windows Server 2012 m/c 上运行。

请注意,前 2 个请求是并发处理的,但每个后续请求需要连续 5 秒。

请注意,前 2 个请求是并发处理的,但每个后续请求需要连续 5 秒。所有请求均在整点后 46 分 39 秒发送。前 2 个请求在每小时 46 分 44 秒得到响应,但最后一个响应在每小时 48 分 14 秒收到。

http://localhost:8895/dostuff?val=5-client-46:39-server-46:44
http://localhost:8895/dostuff?val=1-client-46:39-server-46:44
http://localhost:8895/dostuff?val=2-client-46:39-server-46:49
http://localhost:8895/dostuff?val=6-client-46:39-server-46:54
http://localhost:8895/dostuff?val=3-client-46:39-server-46:59
http://localhost:8895/dostuff?val=4-client-46:39-server-47:4
http://localhost:8895/dostuff?val=7-client-46:39-server-47:9
http://localhost:8895/dostuff?val=9-client-46:39-server-47:14
http://localhost:8895/dostuff?val=8-client-46:39-server-47:19
http://localhost:8895/dostuff?val=10-client-46:39-server-47:24
http://localhost:8895/dostuff?val=11-client-46:39-server-47:29
http://localhost:8895/dostuff?val=12-client-46:39-server-47:34
http://localhost:8895/dostuff?val=13-client-46:39-server-47:39
http://localhost:8895/dostuff?val=14-client-46:39-server-47:44
http://localhost:8895/dostuff?val=15-client-46:39-server-47:49
http://localhost:8895/dostuff?val=16-client-46:39-server-47:54
http://localhost:8895/dostuff?val=18-client-46:39-server-47:59
http://localhost:8895/dostuff?val=17-client-46:39-server-48:4
http://localhost:8895/dostuff?val=19-client-46:39-server-48:9
http://localhost:8895/dostuff?val=0-client-46:39-server-48:14

下面的代码可能会提供一些线索,但我怀疑它更有可能是服务器上的一些配额或节流问题。

// SERVER build with "csc program.cs" run as program.exe
using System;
using System.Net;
using System.Text;
using System.Threading;

class Program
{
    static void Main(string[] args)
    {
        HttpListener listenerLocal = new HttpListener();
        listenerLocal.Prefixes.Add("http://*:8895/");
        listenerLocal.Start();
        while (true)
        {
            //var result = listener.BeginGetContext(RequestCallback, listener);
            var resultLocal = listenerLocal.BeginGetContext((result) =>
            {
                HttpListener listener = (HttpListener)result.AsyncState;
                HttpListenerContext context = listener.EndGetContext(result);
                Thread.Sleep(5000);
                byte[] buffer = Encoding.UTF8.GetBytes(
                    context.Request.Url.OriginalString + string.Format(
                    "-server-{0}:{1}", DateTime.Now.Minute, DateTime.Now.Second));
                context.Response.ContentLength64 = buffer.Length;
                System.IO.Stream output = context.Response.OutputStream;
                output.Write(buffer, 0, buffer.Length);
                output.Close();
            }
            , listenerLocal);
            resultLocal.AsyncWaitHandle.WaitOne();
        }
    }
}

// CLIENT build with "csc program.cs" run as program.exe
using System;
class Program
{
    static void Main(string[] args)
    {
        for (int ii = 0; ii < 20; ii++)
        {
            var thr = new System.Threading.Thread((ctr) =>
            {
                var data = new System.Net.WebClient().OpenRead(
                  string.Format("http://localhost:8895/dostuff?val={0}-client-{1}:{2}"
                  ,ctr, DateTime.Now.Minute, DateTime.Now.Second));
                var reader = new System.IO.StreamReader(data);
                Console.WriteLine(reader.ReadToEnd());
                data.Close();
                reader.Close();
            });
            thr.Start(ii);
        }
        Console.ReadLine();
    }

}

最佳答案

ThreadPool 不是突发任务的最佳选择,您可以使用普通的 Thread

将它用于您的服务器

using System;
using System.Text;
using System.Net;
using System.Threading;

class Program
{
    static void Main(string[] args)
    {
        HttpListener listenerLocal = new HttpListener();
        listenerLocal.Prefixes.Add("http://*:8895/");
        listenerLocal.Start();    

        int count = 0;
        while (true)
        {
            if (count == 20)
                continue;

            Interlocked.Increment(ref count);

            var thr = new Thread(ctr =>
            {
                var l = ctr as HttpListener;
                HttpListenerContext context = l.GetContext();

                Thread.Sleep(5000);

                byte[] buffer = Encoding.UTF8.GetBytes(context.Request.Url.OriginalString + string.Format(
                    "-server-{0}:{1}", DateTime.Now.Minute, DateTime.Now.Second));
                context.Response.ContentLength64 = buffer.Length;
                System.IO.Stream output = context.Response.OutputStream;
                output.Write(buffer, 0, buffer.Length);
                output.Close();

                Interlocked.Decrement(ref count);
            });
            thr.Start(listenerLocal);
        }
    }
}

关于.net - 异步使用的 HttpListener 同步运行,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36941154/

相关文章:

c# - win8中创建DataTemplate

ASP.NET MVC - 在哪里放置数据库查询

javascript - this.$initialize 不是函数

c# - 如何使用 Stylecop 分析器和自定义规则集创建 nuget 包?

.net - 如何访问 WIF 4.5 中的 SecurityTokenHandlers 集合?

c# - 如何发送 HTTP 请求而不处理响应

.net - 将 sqldatasource 绑定(bind)到 asp :label in asp.net 4.0 的正确方法是什么?

php - EventSource 在第一条消息后断开连接

http - 分块编码和内容长度 header

java - IOException 在 http 错误代码返回时在客户端捕获