的TcpListener正在排队的连接速度比我可以清除它们 [英] TcpListener is queuing connections faster than I can clear them

查看:188
本文介绍了的TcpListener正在排队的连接速度比我可以清除它们的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

据我了解,的TcpListener 将排队的连接,一旦你叫开始()。每次调用 AcceptTcpClient (或 BeginAcceptTcpClient ),将出列一个项目从队列中。

As I understand it, TcpListener will queue connections once you call Start(). Each time you call AcceptTcpClient (or BeginAcceptTcpClient), it will dequeue one item from the queue.

如果我们加载通过发送1000个连接到它在一次测试我们的的TcpListener 应用程序,队列建立远快于我们能清除,从而导致(最终)从超时客户端,因为它没有得到回应,因为它的连接仍然在队列中。但是,服务器不会出现得下多少pressure,我们的应用程序没有消耗太多的CPU时间和本机上的其他被监控资源不洒一滴汗水。这感觉就像我们不能有效运行足够的现在。

If we load test our TcpListener app by sending 1,000 connections to it at once, the queue builds far faster than we can clear it, leading (eventually) to timeouts from the client because it didn't get a response because its connection was still in the queue. However, the server doesn't appear to be under much pressure, our app isn't consuming much CPU time and the other monitored resources on the machine aren't breaking a sweat. It feels like we're not running efficiently enough right now.

我们正在调用 BeginAcceptTcpListener 键,然后立即交给一个线程池线程实际上做的工作,然后调用 BeginAcceptTcpClient 了。涉及的工作似乎并没有把任何pressure在机器上,它基本上只有3秒的睡眠之后字典查找,然后一个100字节写入的TcpClient 的流。

We're calling BeginAcceptTcpListener and then immediately handing over to a ThreadPool thread to actually do the work, then calling BeginAcceptTcpClient again. The work involved doesn't seem to put any pressure on the machine, it's basically just a 3 second sleep followed by a dictionary lookup and then a 100 byte write to the TcpClient's stream.

这里的的TcpListener code,我们使用的是:

Here's the TcpListener code we're using:

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

我假设的答案将与使用插槽而不是的TcpListener ,或至少使用 TcpListener.AcceptSocket ,但我想知道我们会去这样做?

I'm assuming the answer will be related to using Sockets instead of TcpListener, or at least using TcpListener.AcceptSocket, but I wondered how we'd go about doing that?

一个想法,我们必须是调用 AcceptTcpClient 立即排队的TcpClient 成多的一个问答LT; TcpClient的> 的对象。这样一来,我们就可以查询在不同的线程这些队列(每线程一个队列),不会导致显示器可能阻塞线程在等待其他出列操作。每个队列线程可以再使用 ThreadPool.QueueUserWorkItem 有一个线程池线程完成的工作,然后移动到出队的接下来的TcpClient 在队列中。你会推荐这种方法,或者是我们的,我们正在使用的问题的TcpListener ,再多迅速出队的是要解决这个问题?

One idea we had was to call AcceptTcpClient and immediately Enqueue the TcpClient into one of multiple Queue<TcpClient> objects. That way, we could poll those queues on separate threads (one queue per thread), without running into monitors that might block the thread while waiting for other Dequeue operations. Each queue thread could then use ThreadPool.QueueUserWorkItem to have the work done in a ThreadPool thread and then move onto dequeuing the next TcpClient in its queue. Would you recommend this approach, or is our problem that we're using TcpListener and no amount of rapid dequeueing is going to fix that?

推荐答案

我已经刮起了直接使用套接字约code,但我缺乏与1000个客户端进行负载测试的手段。能否请你尝试测试如何code比较当前解决方案?我会在结果非常感兴趣,因为我要建一个需要接受大量的连接,以及现在的服务器。

I've whipped up some code that uses sockets directly, but I lack the means of performing a load test with 1000 clients. Could you please try to test how this code compares to your current solution? I'd be very interested in the results as I'm building a server that needs to accept a lot of connections as well right now.

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

这篇关于的TcpListener正在排队的连接速度比我可以清除它们的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆