Question

J'utilise la classe TcpClient en C #.

Chaque fois qu'il ya une nouvelle demande de connexion tcp, la pratique habituelle est de créer un nouveau thread pour le gérer. Et il devrait être possible pour le thread principal de mettre fin à ces threads de gestion à tout moment.

Ma solution pour chacun de ces fils de gestionnaire est la suivante:

1 Check NetworkStream's DataAvailable method
    1.1 If new data available then read and process new data
    1.2 If end of stream then self terminate
2 Check for terminate signal from main thread
    2.1 If terminate signal activated then self terminate
3 Goto 1.

Le problème avec cette approche de vote est que tous ces threads de gestion vont prendre des ressources processeur importantes et surtout s'il y a un grand nombre de ces fils. Cela rend très inefficace.

Y at-il une meilleure façon de le faire?

Était-ce utile?

La solution

Asynchronous Socket Server Exemple pour savoir comment faire la « voie .NET », sans créer de nouvelles discussions pour chaque demande.

Autres conseils

Croyez-le ou pas que 1000 le sommeil de la tique va vraiment garder les choses en cours d'exécution en douceur.

private readonly Queue<Socket> sockets = new Queue<Socket>();
private readonly object locker = new object();
private readonly TimeSpan sleepTimeSpan = new TimeSpan(1000);
private volatile Boolean terminate;

private void HandleRequests() 
{
    Socket socket = null;

    while (!terminate)
    {
        lock (locker)
        {
            socket = null;
            if (sockets.Count > 0)
            {
                socket = sockets.Dequeue();
            }
        }

        if (socket != null)
        {
            // process
        }

        Thread.Sleep(sleepTimeSpan);
    }   
}

Je me souviens de travailler sur un même type de service Windows. Il était un serveur NTRIP qui peut prendre environ 1000 connexions TCP et acheminer les données vers un NTRIP Caster.

Si vous avez un serveur dédié à cette application, alors il ne sera pas un problème sauf si vous ajoutez plus de code à chaque thread (Fichier IO, Base de données, etc - bien que dans mon cas, j'avais aussi le traitement de base de données pour enregistrer l'entrée / sortie pour chaque connexion).

Les choses à surveiller:

  1. bande passante lorsque les fils va jusqu'à 600 ou plus. Vous commencerez à voir déconnexions lorsque la fenêtre TCP tampon est étranglée pour une raison ou la bande passante disponible est inférieur à
  2. Le système d'exploitation sur lequel vous utilisez cette application pourrait avoir certaines restrictions, ce qui peut provoquer des déconnexions

ci-dessus pourrait ne pas être le applicable dans votre cas, mais je voulais juste le mettre ici parce que je faisais face alors au cours du développement.

Vous avez raison que vous ne voulez pas tous vos fils « attente occupé » (à savoir la gestion d'une petite boucle au-dessus et plus). Soit vous voulez bloquer eux, ou que vous souhaitez utiliser E / S asynchrone.

Comme John Saunders mentionné, E / S asynchrones est le « droit chemin » pour ce faire, car il peut évoluer jusqu'à plusieurs centaines de connexions. Fondamentalement, vous appelez BeginRead () et passez une fonction de rappel. BeginRead () retourne immédiatement, et lorsque les données arrive, la fonction de rappel est invoquée sur un thread du pool de fil. La fonction de rappel traite les données, les appels BeginRead () à nouveau, puis retourne, ce qui libère le fil dans la piscine.

Toutefois, si vous ne tiendrez une poignée de connexions ouvertes à la fois, il est parfaitement bien pour créer un fil pour chaque connexion. Au lieu de vérifier la propriété DataAvailable dans une boucle, aller de l'avant et appeler Read (). Le fil se bloque, consommant pas de processeur, jusqu'à ce que les données sont disponibles pour lire. Si la connexion est perdue, ou vous fermez d'un autre fil, l'appel Read () lancera une exception, que vous pouvez gérer en mettant fin à votre fil de lecture.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top