Question sur l’écoute et l’arriéré des sockets

J’écris une application en C # qui doit gérer les connexions entrantes et je n’ai jamais fait de programmation côté serveur auparavant. Cela m’amène aux questions suivantes:

  • Avantages et inconvénients de l’arriéré élevé / faible arriéré? Pourquoi ne devrions-nous pas fixer l’arriéré à un nombre énorme?
  • Si j’appelle Socket.Listen (10), après 10 accept (s) dois-je à nouveau appeler Listen ()? Ou dois-je appeler Listen () après chaque Accept ()?
  • Si je règle le backlog à 0 et que deux personnes souhaitent se connecter à mon serveur en même temps, que se passerait-il? (J’appelle Socket. Sélectionnez une boucle et vérifiez la lisibilité du socket d’écoute. Une fois que j’ai géré la première connexion, la deuxième connexion aboutirait-elle à la prochaine itération si j’appelais à nouveau Listen ()?)

Merci d’avance.

Comme l’a dit Pieter , le backlog d’écoute est une queue utilisée par le système d’exploitation pour stocker les connexions acceptées par la stack TCP mais pas encore par votre programme. Conceptuellement, lorsqu’un client se connecte, il est placé dans cette queue jusqu’à ce que votre code Accept() supprime et le transfère à votre programme.

En tant que tel, le backlog d’écoute est un paramètre de réglage qui peut être utilisé pour aider votre serveur à gérer les pics de tentatives de connexion simultanées. Notez que cela concerne les pics de tentatives de connexion simultanées et n’est en aucun cas lié au nombre maximal de connexions simultanées que votre serveur peut gérer. Par exemple, si vous avez un serveur qui reçoit 10 nouvelles connexions par seconde, il est peu probable que le réglage du backlog d’écoute ait un impact, même si ces connexions durent longtemps et que votre serveur prend en charge 10 000 connexions simultanées (en supposant que votre serveur ne soit pas saturé). la CPU desservant les connexions existantes!). Cependant, si un serveur rencontre occasionnellement de courtes périodes au cours desquelles il accepte 1 000 nouvelles connexions par seconde, vous pouvez probablement empêcher le rejet de certaines connexions en réglant le backlog d’écoute afin de fournir une queue plus longue et donc de donner à votre serveur plus de temps pour appeler Accept() pour chaque connexion.

En ce qui concerne les avantages et les inconvénients, les avantages sont que vous pouvez mieux gérer les pics de tentatives de connexion simultanées et que le système d’exploitation doit allouer plus d’espace à la queue du backlog d’écoute, car elle est plus grande. C’est donc un compromis entre performance et ressources.

Personnellement, je fais du backlog quelque chose qui peut être réglé en externe via un fichier de configuration.

Comment et quand vous appelez écouter et accepter dépend du style de code de socket que vous utilisez. Avec le code synchrone, vous appelez une fois Listen() avec une valeur, disons 10, pour votre backlog d’écoute, puis appelez en boucle Accept() . L’appel à l’écoute définit le sharepoint terminaison auquel vos clients peuvent se connecter et crée de manière conceptuelle la queue du backlog d’écoute de la taille spécifiée. L’appel de Accept() supprime une connexion en attente de la queue du backlog d’écoute, configure un socket pour l’utilisation de l’application et le transmet à votre code en tant que connexion nouvellement établie. Si le code a demandé à votre code d’appeler Accept() , de gérer la nouvelle connexion et de faire un tour en boucle pour appeler Accept() nouveau plus long que l’écart entre les tentatives de connexion simultanées, vous commencerez alors à accumuler des entrées dans la queue du backlog d’écoute.

Avec les sockets asynchrones, cela peut être un peu différent. Si vous utilisez des acceptations asynchrones, vous écouterez une fois, comme auparavant, puis vous en posterez plusieurs (à nouveau configurables) acceptées par asynchrones. Lorsque chacune de ces tâches est terminée, vous gérez la nouvelle connexion et publiez une nouvelle acceptation asynchrone. De cette façon, vous avez une queue d’écoute en attente et une «queue» en attente, ce qui vous permet d’accepter les connexions plus rapidement (de plus, les acceptations asynchrones sont gérées sur les threads du pool de threads, de sorte que vous n’avez pas une seule boucle d’acceptation étroite). Ceci est généralement plus évolutif et vous donne deux points à régler pour gérer davantage de tentatives de connexion simultanées.

Le backlog fournit une queue avec les clients qui tentent de se connecter au serveur, mais que vous n’avez pas encore traités.

Cela concerne le temps écoulé entre le moment où le client se connecte réellement au serveur et le moment où vous Accept ou EndAccept le client.

Si l’acceptation d’un client prend beaucoup de temps, il est possible que le backlog devienne complet et que les nouvelles connexions client soient rejetées jusqu’à ce que vous ayez eu le temps de traiter les clients de la queue.

Concernant vos questions:

  1. Je n’ai pas d’information à ce sujet. Si le numéro par défaut ne pose aucun problème (pas de connexions clientes rejetées), laissez-le par défaut. Si vous constatez de nombreuses erreurs lorsque de nouveaux clients souhaitent se connecter, augmentez le nombre. Cependant, cela sera probablement dû au fait que vous prenez trop de temps à accepter un nouveau client. Vous devriez résoudre ce problème avant d’augmenter l’arriéré;

  2. Non, cela est géré par le système. Le mécanisme normal d’acceptation des clients s’en occupe;

  3. Voir mon explication précédente.

Essayez ce programme et vous verrez ce qui est bon pour l’arriéré.

 using System; using System.Net; using System.Net.Sockets; /* This program creates TCP server socket. Then a large number of clients sortinges to connect it. Server counts connected clients. The number of successfully connected clients depends on the BACKLOG_SIZE parameter. */ namespace BacklogTest { class Program { private const int BACKLOG_SIZE = 0; //<<< Change this to 10, 20 ... 100 and see what happens!!!! private const int PORT = 12345; private const int maxClients = 100; private static Socket serverSocket; private static int clientCounter = 0; private static void AcceptCallback(IAsyncResult ar) { // Get the socket that handles the client request Socket listener = (Socket) ar.AsyncState; listener.EndAccept(ar); ++clientCounter; Console.WriteLine("Connected clients count: " + clientCounter.ToString() + " of " + maxClients.ToString()); // do other some work for (int i = 0; i < 100000; ++i) { } listener.BeginAccept(AcceptCallback, listener); } private static void StartServer() { // Establish the locel endpoint for the socket IPEndPoint localEndPoint = new IPEndPoint(IPAddress.Any, PORT); // Create a TCP/IP socket serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); // Bind the socket to the local endpoint and listen serverSocket.Bind(localEndPoint); serverSocket.Listen(BACKLOG_SIZE); serverSocket.BeginAccept(AcceptCallback, serverSocket); } static void Main(string[] args) { StartServer(); // Clients connect to the server. for (int i = 0; i < 100; ++i) { IPAddress ipAddress = IPAddress.Parse("127.0.0.1"); IPEndPoint remoteEP = new IPEndPoint(ipAddress, PORT); // Create a TCP/IP socket and connect to the server Socket client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); client.BeginConnect(remoteEP, null, null); } Console.ReadKey(); } } }