异步使用的HttpListener同步行为

时间:2016-04-29 14:38:32

标签: .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上运行。

请注意,前两个请求会同时处理,但每个后续请求需要连续5秒。

请注意,前两个请求会同时处理,但每个后续请求需要连续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();
    }

}

1 个答案:

答案 0 :(得分:1)

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);
        }
    }
}