web-dev-qa-db-fra.com

Pourquoi devrais-je utiliser des sockets non bloquants ou bloquants?

Au début, je dois demander ce qui est le meilleur dans quels états? Par exemple, un serveur en temps réel MMORPG. Que faire si je crée un thread par client au lieu d'utiliser des sockets non bloquants? Ou si j'utilise un thread qui contient tous les sockets non bloquants? Can tu m'expliques les avantages?

38
deniz

Votre question mérite une discussion beaucoup plus longue, mais voici un bref coup d'œil à une réponse:

  • l'utilisation de sockets de blocage signifie qu'une seule socket peut être active à tout moment dans un même thread (car elle se bloque en attendant l'activité)
  • l'utilisation de sockets bloquants est généralement plus facile que les sockets non bloquantes (la programmation asynchrone a tendance à être plus compliquée)
  • vous pouvez créer 1 thread par socket comme vous l'avez indiqué, mais les threads ont une surcharge et sont extrêmement inefficaces par rapport aux solutions non bloquantes;
  • avec des sockets non bloquants, vous pouvez gérer un volume de clients beaucoup plus important: il peut atteindre des centaines de milliers en un seul processus - mais le code devient un peu plus compliqué

Avec les sockets non bloquants (sous Windows), vous avez deux options:

  • vote
  • événements basés
  • e/S superposées

Les E/S superposées vous donneront les meilleures performances (milliers de sockets/processus) au détriment d'être le modèle le plus compliqué à comprendre et à implémenter correctement.

Fondamentalement, cela revient à la performance par rapport à la complexité de la programmation.

NOTE

Voici une meilleure explication des raisons pour lesquelles l'utilisation d'un modèle de thread/socket est une mauvaise idée:

Dans Windows, la création d'un grand nombre de threads est très inefficace car le planificateur est incapable de déterminer correctement quels threads devraient recevoir du temps processeur et lesquels ne devraient pas. Cela, couplé à la surcharge de mémoire de chaque thread, signifie que vous manquerez de mémoire (en raison de l'espace de pile) et de cycles de processeur (en raison de la surcharge de gestion des threads) au niveau du système d'exploitation bien avant de manquer de capacité pour gérer les connexions de socket .

33
Mike Dinescu

Je dirai officiellement que pour presque tout sauf les programmes de jouets, vous devez naturellement utiliser des prises non bloquantes.

Le blocage des sockets pose un grave problème: si la machine à l'autre extrémité (ou toute partie de votre connexion à celle-ci) échoue pendant un appel de blocage, votre code finira par être bloqué jusqu'à l'expiration de la pile IP. Dans un cas typique, cela représente environ 2 minutes, ce qui est totalement inacceptable pour la plupart des applications. La seule manière1 abandonner cet appel de blocage, c'est terminer le thread qui l'a créé - mais terminer un thread est lui-même presque toujours inacceptable, car il est essentiellement impossible de nettoyer après lui et de récupérer les ressources qu'il avait allouées. Les sockets non bloquantes rendent trivial l'abandon d'un appel quand/si nécessaire, sans faisant quoi que ce soit au thread qui a fait l'appel.

Il est possible de faire fonctionner les sockets bloquants en quelque sorte si vous utilisez un modèle multi-processus à la place. Ici, vous générez simplement un processus entièrement nouveau pour chaque connexion. Ce processus utilise un socket bloquant, et quand/si quelque chose se passe mal, vous tuez tout le processus. Le système d'exploitation sait comment nettoyer les ressources d'un processus, donc le nettoyage n'est pas un problème. Cependant, il a encore d'autres problèmes potentiels: 1) vous avez à peu près besoin d'un moniteur de processus pour tuer les processus en cas de besoin, et 2) la génération d'un processus est généralement beaucoup plus coûteuse que la simple création d'un socket. Néanmoins, cela peut être une option viable, surtout si:

  1. Vous traitez avec un petit nombre de connexions à la fois
  2. Vous effectuez généralement un traitement approfondi pour chaque connexion
  3. Vous ne traitez qu'avec des hôtes locaux, votre connexion avec eux est donc rapide et fiable
  4. Vous êtes plus soucieux d'optimiser le développement que l'exécution

1. Eh bien, techniquement, ce n'est pas le seulement moyen possible, mais la plupart des alternatives sont relativement laides - pour être plus précis, je pense qu'au moment où vous ajoutez du code pour comprendre qu'il y a un problème, et puis résolvez le problème, vous avez probablement fait plus de travail que si vous utilisez simplement un socket non bloquant.

11
Jerry Coffin