据我了解,TcpListener
一旦您调用Start()
. 每次调用AcceptTcpClient
(or BeginAcceptTcpClient
) 时,它都会从队列中取出一项。
如果我们通过一次向它发送 1,000 个连接来加载测试我们的TcpListener
应用程序,队列的构建速度远远快于我们清除它的速度,导致(最终)客户端超时,因为它没有得到响应,因为它的连接仍在队列。但是,服务器似乎没有太大压力,我们的应用程序没有消耗太多 CPU 时间,并且机器上的其他受监控资源也没有出汗。感觉我们现在的运行效率不够高。
我们正在调用BeginAcceptTcpListener
,然后立即移交给一个ThreadPool
线程来实际完成工作,然后BeginAcceptTcpClient
再次调用。所涉及的工作似乎并没有给机器带来任何压力,它基本上只是 3 秒的睡眠,然后是字典查找,然后是 100 字节的写入TcpClient
流。
这是TcpListener
我们正在使用的代码:
// Thread signal.
private static ManualResetEvent tcpClientConnected = new ManualResetEvent(false);
public void DoBeginAcceptTcpClient(TcpListener listener)
{
// Set the event to nonsignaled state.
tcpClientConnected.Reset();
listener.BeginAcceptTcpClient(
new AsyncCallback(DoAcceptTcpClientCallback),
listener);
// Wait for signal
tcpClientConnected.WaitOne();
}
public void DoAcceptTcpClientCallback(IAsyncResult ar)
{
// Get the listener that handles the client request, and the TcpClient
TcpListener listener = (TcpListener)ar.AsyncState;
TcpClient client = listener.EndAcceptTcpClient(ar);
if (inProduction)
ThreadPool.QueueUserWorkItem(state => HandleTcpRequest(client, serverCertificate)); // With SSL
else
ThreadPool.QueueUserWorkItem(state => HandleTcpRequest(client)); // Without SSL
// Signal the calling thread to continue.
tcpClientConnected.Set();
}
public void Start()
{
currentHandledRequests = 0;
tcpListener = new TcpListener(IPAddress.Any, 10000);
try
{
tcpListener.Start();
while (true)
DoBeginAcceptTcpClient(tcpListener);
}
catch (SocketException)
{
// The TcpListener is shutting down, exit gracefully
CheckBuffer();
return;
}
}
我假设答案将与 usingSockets
而不是TcpListener
或至少 using相关TcpListener.AcceptSocket
,但我想知道我们将如何去做?
我们的一个想法是AcceptTcpClient
立即调用多个对象之一。这样,我们可以在不同的线程上轮询这些队列(每个线程一个队列),而不会遇到可能在等待其他操作时阻塞线程的监视器。然后,每个队列线程可以用来在一个线程中完成工作,然后继续将其队列中的下一个出队。你会推荐这种方法,还是我们正在使用的问题,并且没有任何快速出队可以解决这个问题?Enqueue
TcpClient
Queue<TcpClient>
Dequeue
ThreadPool.QueueUserWorkItem
ThreadPool
TcpClient
TcpListener