Mat*_*ley 9 .net c# sockets tcplistener tcpclient
据我了解,TcpListener一旦你打电话就会排队连接Start().每次调用AcceptTcpClient(或BeginAcceptTcpClient)时,它都会从队列中出列一个项目.
如果我们TcpListener通过立即向它发送1,000个连接来加载测试我们的应用程序,那么队列构建的速度远远超过我们清除它的速度,导致(最终)从客户端超时,因为它没有得到响应,因为它的连接仍在队列.但是,服务器似乎没有太大的压力,我们的应用程序不会消耗太多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;
}
}
Run Code Online (Sandbox Code Playgroud)
我假设答案将与使用Sockets而不是TcpListener或至少使用相关TcpListener.AcceptSocket,但我想知道我们将如何做到这一点?
我们有一个想法是调用AcceptTcpClient,并立即Enqueue将TcpClient多个成一个Queue<TcpClient>对象.这样,我们可以在不同的线程(每个线程一个队列)上轮询这些队列,而不会运行到可能在等待其他Dequeue操作时阻塞线程的监视器.然后,每个队列线程可以使用ThreadPool.QueueUserWorkItem在ThreadPool线程中完成工作,然后继续将TcpClient队列中的下一个队列出列.你会推荐这种方法,还是我们正在使用的问题,TcpListener而且没有多少快速出列会解决这个问题?
我已经编写了一些直接使用套接字的代码,但我缺乏对 1000 个客户端执行负载测试的方法。您能否尝试测试一下这段代码与您当前的解决方案相比如何?我对结果非常感兴趣,因为我正在构建一个现在也需要接受大量连接的服务器。
static WaitCallback handleTcpRequest = new WaitCallback(HandleTcpRequest);
static void Main()
{
var e = new SocketAsyncEventArgs();
e.Completed += new EventHandler<SocketAsyncEventArgs>(e_Completed);
var socket = new Socket(
AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
socket.Bind(new IPEndPoint(IPAddress.Loopback, 8181));
socket.Listen((int)SocketOptionName.MaxConnections);
socket.AcceptAsync(e);
Console.WriteLine("--ready--");
Console.ReadLine();
socket.Close();
}
static void e_Completed(object sender, SocketAsyncEventArgs e)
{
var socket = (Socket)sender;
ThreadPool.QueueUserWorkItem(handleTcpRequest, e.AcceptSocket);
e.AcceptSocket = null;
socket.AcceptAsync(e);
}
static void HandleTcpRequest(object state)
{
var socket = (Socket)state;
Thread.Sleep(100); // do work
socket.Close();
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
11879 次 |
| 最近记录: |