单声道中的HttpListener可以';t在同一时间内处理2个以上的请求
本文关键字:同一时间 处理 请求 2个 声道 可以 HttpListener 单声道 | 更新日期: 2023-09-27 18:25:40
我在mono中使用HttpListener处理多线程http请求时遇到了问题。看起来httpListener.BeginGetContext(_handleRequestCallback,null)不能"同时"处理2个以上的请求。我写了一个小测试:
using System;
using System.Net;
using NUnit.Framework;
using System.IO;
using log4net;
using System.Threading;
namespace Other
{
public class ListenerTest
{
private ILog _log;
private HttpListener _httpListener;
private const int PORT = 8080;
private const int REQUESTS = 20;
private AsyncCallback _handleRequestCallback;
[TestFixtureSetUp]
public void SetUp()
{
ServicePointManager.DefaultConnectionLimit = REQUESTS;
ThreadPool.SetMinThreads(REQUESTS, REQUESTS);
ThreadPool.SetMaxThreads(REQUESTS, REQUESTS);
_httpListener = new HttpListener();
_httpListener.Prefixes.Add(String.Format("http://*:{0}/", PORT));
_httpListener.Start();
_handleRequestCallback = new AsyncCallback(processAsync);
_log = LogManager.GetLogger(typeof(ListenerTest));
}
[Test]
public void SyncTest()
{
Thread serverThread = new Thread(() => processSyncThread());
serverThread.Start();
for(int i = 0; i < REQUESTS; ++i)
{
makeRequest(i.ToString(), HttpStatusCode.OK, 1000);
}
}
[Test]
public void AsyncTest()
{
int serverThreads = 5;
Thread serverThread = new Thread(() => processAsyncThread(serverThreads));
serverThread.Start();
for(int i = 0; i < REQUESTS; ++i)
{
int position = i;
Thread thread = new Thread(() => makeRequest(position.ToString(), HttpStatusCode.OK, 5000));
thread.Start();
}
Thread.Sleep(5000);
}
private void processAsyncThread(int threads)
{
for(int i = 0; i < threads; ++i)
_httpListener.BeginGetContext(_handleRequestCallback, null);
}
private void processAsync(IAsyncResult asyncResult)
{
Thread thread = new Thread(() => processSync(_httpListener.EndGetContext(asyncResult)));
thread.Start();
// processSync(_httpListener.EndGetContext(asyncResult));
_httpListener.BeginGetContext(_handleRequestCallback, null);
}
private void processSyncThread()
{
while(true)
{
var context = _httpListener.GetContext();
processSync(context);
}
}
private void processSync(HttpListenerContext context)
{
string request = context.Request.RawUrl.TrimStart('/');
_log.InfoFormat("Received request:{0}", request);
Thread.Sleep(500);
using(StreamWriter writer = new StreamWriter(context.Response.OutputStream))
writer.Write(request);
_log.InfoFormat("Sent response for:{0}", request);
}
private string makeRequest(string request, HttpStatusCode expectedCode, int timeout)
{
_log.InfoFormat("Sending {0} request.", request);
WebRequest webRequest = WebRequest.Create(String.Format("http://localhost:{0}/{1}", PORT, request));
webRequest.Timeout = timeout;
try
{
HttpWebResponse response = (HttpWebResponse)webRequest.GetResponse();
if(expectedCode != response.StatusCode)
throw new IOException(String.Format(
"Returned unexpected status code: {0} for request: {1} when expected: {2}",
response.StatusCode, request, expectedCode));
StreamReader reader = new StreamReader(response.GetResponseStream());
string responseContent = reader.ReadToEnd();
response.Close();
_log.InfoFormat("Received response:{0}", responseContent);
return responseContent;
}
catch(WebException exception)
{
if (exception.Response is HttpWebResponse
&& expectedCode == ((HttpWebResponse)exception.Response).StatusCode)
return "";
else if (exception.Status == WebExceptionStatus.Timeout
&& expectedCode == HttpStatusCode.RequestTimeout)
return "";
throw;
}
}
}
}
(这需要Nunit和log4net运行,但它们可能很容易被删除)有了SyncTest,一切如愿以偿。在AsyncTest中,我看到httpListener并行调用_handleRequestCallback的次数不会超过2次。第三个请求在处理任何先前请求时开始处理:
01:24:23,788 [(null)-27] INFO Other.ListenerTest {(null)} - Sending 10 request.
01:24:23,788 [(null)-30] INFO Other.ListenerTest {(null)} - Sending 13 request.
...
01:24:23,788 [(null)-23] INFO Other.ListenerTest {(null)} - Sending 8 request.
01:24:23,793 [(null)-36] INFO Other.ListenerTest {(null)} - Sending 19 request.
01:24:23,885 [(null)-40] INFO Other.ListenerTest {(null)} - Received request:12
01:24:23,885 [(null)-39] INFO Other.ListenerTest {(null)} - Received request:5
01:24:24,400 [(null)-39] INFO Other.ListenerTest {(null)} - Sent response for:5
01:24:24,400 [(null)-40] INFO Other.ListenerTest {(null)} - Sent response for:12
01:24:24,413 [(null)-20] INFO Other.ListenerTest {(null)} - Received response:5
01:24:24,414 [(null)-29] INFO Other.ListenerTest {(null)} - Received response:12
01:24:24,414 [(null)-54] INFO Other.ListenerTest {(null)} - Received request:0
01:24:24,414 [(null)-53] INFO Other.ListenerTest {(null)} - Received request:15
01:24:24,915 [(null)-54] INFO Other.ListenerTest {(null)} - Sent response for:0
01:24:24,915 [(null)-53] INFO Other.ListenerTest {(null)} - Sent response for:15
01:24:24,917 [(null)-15] INFO Other.ListenerTest {(null)} - Received response:0
01:24:24,918 [(null)-32] INFO Other.ListenerTest {(null)} - Received response:15
01:24:24,919 [(null)-65] INFO Other.ListenerTest {(null)} - Received request:18
01:24:24,919 [(null)-66] INFO Other.ListenerTest {(null)} - Received request:3
01:24:25,419 [(null)-65] INFO Other.ListenerTest {(null)} - Sent response for:18
01:24:25,420 [(null)-66] INFO Other.ListenerTest {(null)} - Sent response for:3
01:24:25,458 [(null)-18] INFO Other.ListenerTest {(null)} - Received response:3
01:24:25,458 [(null)-77] INFO Other.ListenerTest {(null)} - Received request:10
01:24:25,558 [(null)-35] INFO Other.ListenerTest {(null)} - Received response:18
01:24:25,558 [(null)-80] INFO Other.ListenerTest {(null)} - Received request:6
01:24:25,959 [(null)-77] INFO Other.ListenerTest {(null)} - Sent response for:10
01:24:25,998 [(null)-27] INFO Other.ListenerTest {(null)} - Received response:10
01:24:25,998 [(null)-81] INFO Other.ListenerTest {(null)} - Received request:4
01:24:26,059 [(null)-80] INFO Other.ListenerTest {(null)} - Sent response for:6
01:24:26,059 [(null)-21] INFO Other.ListenerTest {(null)} - Received response:6
01:24:26,060 [(null)-82] INFO Other.ListenerTest {(null)} - Received request:2
我在MS.Net上运行相同的代码(但没有log4net),看看我期望的是什么:
01:38:39:754 Sending 9 request.
01:38:39:738 Sending 5 request.
01:38:39:738 Sending 3 request.
01:38:39:738 Sending 1 request.
01:38:40:660 Received request:18
01:38:40:660 Received request:1
01:38:40:660 Received request:0
01:38:40:660 Received request:2
01:38:40:660 Received request:3
01:38:40:660 Received request:4
01:38:40:676 Received request:5
01:38:40:676 Received request:6
01:38:40:676 Received request:7
01:38:40:676 Received request:8
01:38:40:692 Received request:9
01:38:40:692 Received request:10
01:38:40:692 Received request:11
01:38:40:692 Received request:12
01:38:40:707 Received request:13
01:38:40:707 Received request:14
01:38:40:707 Received request:15
01:38:40:707 Received request:16
01:38:40:723 Received request:17
01:38:40:723 Received request:19
01:38:41:160 Sent response for:4
01:38:41:160 Received response:18
01:38:41:160 Received response:1
01:38:41:160 Sent response for:3
01:38:41:160 Sent response for:2
01:38:41:176 Received response:8
01:38:41:160 Sent response for:1
01:38:41:160 Sent response for:0
01:38:41:160 Sent response for:18
01:38:41:160 Received response:2
01:38:41:160 Received response:3
01:38:41:160 Received response:4
01:38:41:176 Sent response for:8
01:38:41:176 Sent response for:7
01:38:41:176 Sent response for:6
01:38:41:176 Sent response for:5
01:38:41:176 Received response:7
01:38:41:176 Received response:6
01:38:41:176 Received response:5
01:38:41:192 Received response:9
01:38:41:192 Sent response for:9
01:38:41:192 Received response:10
01:38:41:192 Sent response for:10
01:38:41:192 Received response:11
01:38:41:192 Sent response for:11
01:38:41:192 Received response:12
01:38:41:192 Sent response for:12
01:38:41:160 Received response:0
01:38:41:207 Received response:16
01:38:41:207 Sent response for:16
01:38:41:223 Sent response for:19
01:38:41:223 Received response:19
01:38:41:223 Sent response for:13
01:38:41:223 Sent response for:14
01:38:41:223 Sent response for:15
01:38:41:223 Sent response for:17
01:38:41:238 Received response:13
01:38:41:238 Received response:14
01:38:41:238 Received response:15
01:38:41:223 Received response:17
我认为这个问题可能与这个问题有关,但建议的解决方案不起作用。那么,有人对变通方法有想法吗?
Mono 2.10太旧,请使用Mono 3.2.x 进行测试
如果您在这个版本中仍然面临同样的问题,那么尝试使用更新的版本:编译您自己的mono(主分支),因为刚刚实现并推送了一个新的标志"--server"。