TcpListener ist queuing-verbindungen schneller als ich kann Sie löschen

Wie ich es verstehe, TcpListener Warteschlange, die verbindungen, sobald Sie rufen Start(). Jedes mal, wenn Sie anrufen AcceptTcpClient (oder BeginAcceptTcpClient), wird er aus der Warteschlange entfernt ein Element aus der Warteschlange.

Wenn wir laden, testen unsere TcpListener app durch senden von 1.000 verbindungen, um es auf einmal, die Warteschlange baut sich weit schneller als wir es klar, führt (eventuell) zu timeouts vom client, da es nicht eine Antwort zu bekommen, denn die Verbindung war noch in der Warteschlange. Jedoch wird der server nicht angezeigt unter viel Druck, unsere app nicht verbrauchen viel CPU-Zeit und die anderen überwachten Ressourcen auf dem Rechner nicht ins Schwitzen zu geraten. Es fühlt sich an wie wir sind, läuft nicht effizient genug, gerade jetzt.

Wir fordern BeginAcceptTcpListener und dann sofort die übergabe an eine ThreadPool thread, um tatsächlich tun die Arbeit, dann ruft BeginAcceptTcpClient wieder. Der Arbeitsaufwand scheint nicht Druck auf die Maschine, es ist im Grunde nur eine 3-Sekunden-Schlaf, gefolgt von einem Wörterbuch nachschlagen und dann ein 100 byte schreiben, um die TcpClient's stream.

Hier ist die TcpListener code verwenden wir:

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

Ich nehme an die Antwort wird im Zusammenhang mit der Verwendung Sockets statt TcpListener oder zumindest mit TcpListener.AcceptSocket werden, aber ich fragte mich, wie würden wir tun?

Einer Idee, die wir hatten, war ein Telefonat mit AcceptTcpClient und sofort Enqueue die TcpClient in einer von mehreren Queue<TcpClient> Objekte. So, könnten wir Umfrage die Warteschlangen in separaten threads (eine queue pro thread), ohne Monitore, die blockieren könnten den thread während der Wartezeit für andere Dequeue Operationen. Jede queue thread könnte dann ThreadPool.QueueUserWorkItem zu haben, die Arbeit in einem ThreadPool thread und bewegen Sie dann auf entfernen am nächsten TcpClient in der Warteschlange. Würden Sie empfehlen diese Vorgehensweise, oder ist unser problem, dass wir TcpListener und kein Betrag der schnelle dequeueing wird, dass zu beheben?

  • Ich denke, Sie haben vielleicht eine irrige Annahme. Die eingehenden verbindungen werden verworfen, nicht fallen gelassen aus der Schlange. Sie haben es nie in die Warteschlange, weil die queue war bereits voll. Sie haben die option eine größere Länge der Warteschlange. Das wird das problem zu lindern etwas. Das eigentliche problem ist, dass es nicht sehr realistisch-slam-server mit verbindet schnell. Ein server, der ist gebaut, um zu behandeln 1k-clients in der Regel noch erfordert die Verbindung zu kommen in auf einem getakteten Tempo.
  • Versuchen Sie, diese mit einer größeren "Nachholbedarf" Wert: "msdn.microsoft.com/en-us/library/5kh8wf6s(v=VS.100).aspx
  • MSDN sagt, dass der TcpListener eine SocketException ausgelöst, wenn die queue-Größe ist überschritten, ich habe nicht gesehen, alle SocketExceptions (die CheckBuffer Methode logs), also bin ich davon ausgegangen, ich hatte nicht die Größenbeschränkung erreicht noch. Aber das ist ein guter Punkt re 1k-verbindungen.
  • Nur um zu klären, diejenigen, die SocketExceptions geworfen werden, auf dem client, nicht der server.
Schreibe einen Kommentar