私が理解しているように、TcpListener
を呼び出すと、 は接続をキューに入れますStart()
。AcceptTcpClient
(または)を呼び出すたびにBeginAcceptTcpClient
、キューから 1 つのアイテムがデキューされます。
一度に 1,000 の接続をアプリに送信して負荷テストを行うTcpListener
と、キューはクリアするよりもはるかに速く構築され、(最終的には) クライアントからのタイムアウトにつながります。列。ただし、サーバーに負荷がかかっているようには見えず、アプリは CPU 時間をあまり消費しておらず、マシン上で監視されている他のリソースも十分に機能していません。現在、私たちは十分に効率的に運営されていないように感じます。
呼び出しBeginAcceptTcpListener
てすぐにスレッドに引き渡し、ThreadPool
実際に作業を実行してから、BeginAcceptTcpClient
再度呼び出します。関連する作業は、マシンに圧力をかけるようには見えません。基本的には、3 秒間のスリープとそれに続く辞書の検索、そしてTcpClient
のストリームへの 100 バイトの書き込みです。
使用している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;
}
}
答えは のSockets
代わりにを使用するTcpListener
か、少なくとも を使用することに関連してTcpListener.AcceptSocket
いると思いますが、どうやってそれを行うのだろうかと思いました。
私たちが持っていたアイデアの 1 つは、 を呼び出してAcceptTcpClient
、すぐに複数のオブジェクトの 1 つに入れるというものでした。そうすれば、別のスレッド (スレッドごとに 1 つのキュー) でこれらのキューをポーリングでき、他の操作を待っている間にスレッドをブロックする可能性のあるモニターに遭遇することはありません。次に、各キュー スレッドを使用して、スレッド内で作業を完了させ、そのキュー内の次のキューからの取り出しに移ることができます。このアプローチをお勧めしますか、それとも私たちが使用している問題であり、迅速なデキューでは解決されませんか?Enqueue
TcpClient
Queue<TcpClient>
Dequeue
ThreadPool.QueueUserWorkItem
ThreadPool
TcpClient
TcpListener