TcpListener est de files d'attente des connexions plus vite que je peux les effacer

Comme je le comprends, TcpListener aura la file d'attente de connexions une fois que vous appelez Start(). Chaque fois que vous appelez AcceptTcpClient (ou BeginAcceptTcpClient), il va retirer un élément de la file d'attente.

Si nous charger de tester notre TcpListener application par l'envoi de 1 000 connexions à la fois, la file d'attente s'appuie beaucoup plus vite que nous pouvons l'effacer, conduisant éventuellement à des délais d'attente de la part du client, car il n'a pas obtenu une réponse parce que sa connexion est toujours dans la file d'attente. Toutefois, le serveur ne semble pas être sous beaucoup de pression, notre application n'est pas en consommer beaucoup de temps PROCESSEUR et les autres ressources surveillées sur la machine ne sont pas casser une sueur. Il se sent comme nous ne sommes pas en cours d'exécution assez efficace de la droite maintenant.

Nous appelons BeginAcceptTcpListener, puis immédiatement à la remise à un ThreadPool thread réellement faire le travail, puis de l'appel d' BeginAcceptTcpClient de nouveau. Le travail ne semble pas mettre de pression sur la machine, il est fondamentalement juste 3 seconde de sommeil suivie par une recherche dans le dictionnaire et puis un 100 octets à écrire à l' TcpClient's de flux.

Voici la TcpListener code que nous avons utilisé:

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

Je suis en supposant que la réponse va être liés à l'utilisation de Sockets au lieu de TcpListener, ou au moins à l'aide TcpListener.AcceptSocket, mais je me demandais comment nous allions faire cela?

Une idée que nous avions était d'appel AcceptTcpClient et immédiatement Enqueue la TcpClient dans l'une des multiples Queue<TcpClient> objets. De cette façon, nous pourrions sondage de ces files d'attente sur des threads séparés (une file d'attente par thread), sans que des moniteurs qui pourraient bloquer le thread en attendant que d'autres Dequeue opérations. Chaque file d'attente thread pourrait ensuite utiliser ThreadPool.QueueUserWorkItem pour que le travail soit fait dans un ThreadPool fil et puis déplacez-vous sur la file d'attente de la prochaine TcpClient dans sa file d'attente. Recommanderiez-vous cette approche, ou notre problème est que nous sommes à l'aide de TcpListener et aucune quantité de rapide dequeueing est à résoudre ce problème?

Je pense que vous pourriez avoir une supposition erronée. Les connexions entrantes qui sont laissés de côté, ne sont pas supprimés de la file d'attente. Ils ont jamais fait dans la file d'attente parce que la file d'attente était déjà complet. Vous avez la possibilité de spécifier une plus grande longueur de file d'attente. Qui permettront de soulager un peu le problème. Le vrai problème, c'est qu'il n'est pas très réaliste à claquer le serveur se connecte rapidement. Un serveur qui est construit pour gérer 1k clients en général il faut encore le relie à un rythme mesuré.
Essayez cela avec plus d'un "carnet de commandes" valeur: msdn.microsoft.com/en-us/library/5kh8wf6s(v=VS.100).aspx
MSDN dit que le TcpListener va lancer une exception socketexception si la taille de file d'attente est dépassé, je n'ai pas vu de SocketExceptions (le CheckBuffer méthode de journaux), donc j'ai supposé que je n'avais pas atteint sa limite de taille encore. Mais c'est un bon point de re 1k connexions.
Juste pour préciser, ces SocketExceptions sont jetés sur le client, pas sur le serveur.

OriginalL'auteur Matthew Brindley | 2010-04-30