2017-03-24 6 views
0

Comment configurer des sockets IOCP pour plusieurs écouteurs (sur différents ports)? Chaque exemple que je trouve en ligne est juste un seul serveur - exemple de clients multiples, et je ne comprends pas si je devais créer plusieurs IOCPs, ou utiliser seulement un pour tous les auditeurs en quelque sorte?Utilisation d'IOCP avec plusieurs écouteurs

Par exemple, j'ai trouvé this example on GitHub, ce qui semble être une légère modification de un code de SDK Windows 7, et ce code crée un seul port d'achèvement pour une seule prise d'écouteur:

g_hIOCP = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0); 

for(DWORD dwCPU = 0; dwCPU < g_dwThreadCount; dwCPU++) 
{ 
    ... 
    // associate worker thread with this iocp 
    hThread = CreateThread(NULL, 0, WorkerThread, g_hIOCP, 0, &dwThreadId); 
    ... 
} 

Comment est-ce que j'utilise ce même pool de threads pour plusieurs ports d'achèvement? Ou dois-je d'une manière ou d'une autre seulement besoin d'un port d'achèvement pour toutes les sockets d'écoute?

+0

Je ne sais pas si cela peut aider, mais j'ai cet exemple enregistré: http://www.serverframework.com/asynchronousevents/2012/03/windows-8-registered-io---multi-threaded-rio -iocp-udp-example -server.html – lsalamon

Répondre

1

vous avez seulement besoin un port d'achèvement pour toutes les sockets d'écoute. et plusieurs threads (pool de threads) qui seront écoutés sur ce port d'achèvement. aussi possible de ne pas vous diriger créer le port d'achèvement et le pool de threads, mais déléguer cette tâche à system (ntdll). cela peut être fait en utilisant BindIoCompletionCallback ou CreateThreadpoolIo

donc nous avons - seul port d'achèvement, plusieurs threads de travail d'écoute de ce port (de nombre habituel de fils == nombre de cœurs de processeur) et plusieurs fichiers (prises) associés à cette le port d'achèvement par BindIoCompletionCallback ou CreateThreadpoolIo ou CreateIOCompletionPort (logique laid - comparer avec ZwSetInformationFile(..FileCompletionInformation) qui est utilisé en interne)

1

Lors de l'initialisation du système serveur, lancer un appel AcceptEx() pour chaque port qui doit l'avoir. En utilisant une structure OVERLAPPED étendue de la manière "habituelle", transférez les sockets d'écoute et de client vers le thread qui gère l'événement d'achèvement d'E/S. Le thread de gestionnaire a alors accès à toutes les données par écouteur et par client lorsqu'il s'exécute et peut ainsi prendre les mesures appropriées. Notez attentivement qu'un ou deux éléments de données peuvent nécessiter un verrou et/ou une file d'attente pour empêcher plusieurs threads de pool de modifier les données en raison, disons, de deux clients se connectant en même temps.

Il n'y a pas besoin d'un port d'achèvement/pool par écouteur, un pool est correct.

Le thread de gestionnaire doit également émettre un autre AcceptEx() pour le prochain client auquel se connecter.

1

les autres réponses sur ce fil sont totalement légitimes mais je crois que je peux ajouter un peu à lui. Discutons ce qu'est un port d'achèvement, comme je le comprends.

Un port d'achèvement est un récepteur d'événements. C'est-à-dire qu'un événement se produit, un port d'achèvement est notifié.

Maintenant, il y a bien sûr une grande taxonomie d'événements. Le port d'achèvement est bien adapté aux événements d'un type particulier: les compléments d'E/S. Il y a un brevet de Cutler et de gang écrit dans un langage étonnamment lisible par l'homme, qui décrit comment IOCP s'intègre au noyau NT. Récapitulatif: un port d'achèvement est un récepteur d'événements bien adapté à la réception de notifications de complétions d'E/S.

Maintenant, nous allons revenir à la question de l'OP:

Comment puis-je configurer prises IOCP pour plusieurs auditeurs (sur des ports différents)?

Votre événement est une réalisation d'un appel AcceptEx() précédente. Il s'agit généralement d'un appel connect() côté client, mais il peut également s'agir d'une désactivation de votre carte réseau. Vous décidez d'abord si vous souhaitez que les connexions sur le même port soient traitées simultanément ou en série. Aussi, vous devez décider si vous voulez avoir des connexions sur différents ports à traiter simultanément ou en série.

Je vois trois approches possibles:

  • toutes les complétions de connexion sont sérialisés

CreateIOCompletionPort dès le départ une fois, BindIOCompletionCallback à pour chaque auditeur, un thread de travail qui appelle GetQueuedCompletionStatus comme RbMm décrit

  • les complétions de connexion du même écouteur (sur le même port) sont sérialisées, mais la connexion est terminée ions sur des ports différents sont en même temps

vous devez créer un port d'achèvement par auditeur et tourner un travailleur qui va GetQueuedCompletionStatus()

  • toutes les complétions de connexion sont simultanées

Vous pouvez avoir un port d'achèvement, mais vous obtenez plusieurs threads pour appeler GetQueuedCompletionStatus()

Vous n'êtes pas nécessairement limité à avoir igs comme je l'ai décrit ci-dessus. Les ports d'achèvement sont intelligents, vous pouvez donc utiliser un port et plusieurs serveurs, et les serveurs acquièrent des verrous par écouteur pour la sérialisation. Les machines du port d'achèvement dans le noyau comprendront que vous avez bloqué et relâché d'autres serveurs si nécessaire.

Récapitulatif: tout d'abord, vous décidez de la manière dont vous voulez être concurrentiel. Ensuite, vous choisissez le nombre de ports d'achèvement dont vous avez besoin.