Problèmes d’implémentation d’un serveur UDP multithread (threadpool?)

J’écris actuellement un streamer audio (client-serveur) (C / C ++) et j’ai décidé de créer un serveur UDP multi-thread pour ce projet.

La logique derrière cela est que chaque client sera traité dans son propre thread. Les problèmes que je rencontre sont l’interférence des fils entre eux.

La première chose que fait mon serveur est de créer une sorte de pool de threads. il crée 5 threads qui sont tous bloqués automatiquement par une fonction recvfrom() , bien qu’il semble que, la plupart du temps, lorsque je connecte un autre périphérique au serveur, plusieurs threads répondent et que, par la suite, le serveur est bloqué entièrement et ne pas fonctionner plus loin.

Il est assez difficile de déboguer cela aussi, alors j’écris ici pour obtenir des conseils sur la manière dont les serveurs UDP multithreads sont implémentés.

Devrais-je utiliser un mutex ou un sémaphore dans une partie du code? Si oui où?

Toutes les idées seraient extrêmement utiles.

Prenez du recul: vous dites

chaque client sera traité dans son propre fil

mais UDP n’est pas orienté connexion. Si tous les clients utilisent la même adresse de multidiffusion, il n’y a pas de moyen naturel de décider quel thread doit gérer un paquet donné.


Si vous êtes persuadé que chaque client a son propre fil (ce que je conseillerais généralement, mais cela peut avoir un sens ici), vous avez besoin d’un moyen de déterminer le client de chaque paquet.

Cela signifie soit

  • en utilisant TCP (puisque vous semblez essayer de toute façon un comportement orienté connexion)
  • lire chaque paquet, déterminer la connexion client logique à laquelle il appartient et l’envoyer au bon thread. Notez que puisque les informations de routage sont globales / partagées, les deux sont équivalentes:

    1. conserver une IP source -> mappage de threads, protégé par un mutex, lecture et access depuis tous les threads
    2. faire toutes les lectures dans un seul thread, utiliser une adresse IP source locale -> mappage de threads

    Le premier semble être ce que vous recherchez, mais sa conception est médiocre. Lorsqu’un paquet arrive, vous réveillez un thread, puis il verrouille le mutex et effectue la recherche, et éventuellement réveille un autre thread. Le thread que vous voulez gérer cette connexion peut également être bloqué en lecture, vous avez donc besoin d’un mécanisme pour l’activer.

    La seconde donne au moins une séparation des problèmes (lecture / envoi / traitement).


Sensiblement, votre conception devrait dépendre de

  • nombre de clients
  • Charge I / O
  • quantité de traitement non-I / O (ou IO: ratio CPU, ou …)

La première chose que fait mon serveur est de créer une sorte de pool de threads. il crée 5 threads qui sont tous bloqués automatiquement par une fonction recvfrom (), bien qu’il semble que, la plupart du temps, lorsque je connecte un autre périphérique au serveur, plusieurs threads répondent et que, par la suite, le serveur est entièrement bloqué et ne plus fonctionner

Plutôt que de placer tous vos threads sur une recvfrom () sur la même connexion de socket, vous devez protéger la connexion avec un sémaphore et laisser vos threads de travail attendre le sémaphore. Lorsqu’un thread acquiert le sémaphore, il peut appeler recvfrom () et lorsqu’il renvoie un paquet, il peut libérer le sémaphore (pour qu’un autre thread puisse l’acquérir) et gérer le paquet lui-même. Une fois le paquet traité, il peut revenir à attendre sur le sémaphore. De cette façon, vous évitez de transférer des données entre les threads.

Votre recvfrom doit être dans le thread principal et lorsqu’il reçoit des données, vous devez transmettre l’adresse IP: Port et les données du client UDP aux threads auxiliaires.

Passer l’adresse IP: le port et les données peuvent être effectués en créant un nouveau thread à chaque fois que le thread principal reçoit un paquet UDP ou peut être transmis aux threads auxiliaires via une queue de messages.

Je pense que votre principal problème est la connexion udp non persistante. Udp ne maintient pas vos connexions en vie, il n’échange que deux datagrammes par session. Dans le pire des cas, en fonction de votre application, des threads simultanés lisent les premières informations disponibles, c’est-à-dire que recvfrom () débloquera même si ce n’est pas à son tour de le faire.

Je pense que la solution consiste à utiliser select dans le thread principal et, avec un tampon simultané, à gérer ce que fera le thread. Dans cette solution, vous pouvez avoir un thread par client, ou un thread par fichier, en supposant que vous gardiez les informations nécessaires sur les clients pour vous assurer que vous envoyez la bonne partie du fichier.

TCP est un autre moyen de le faire, car il maintient la connexion active pour chaque thread que vous exécutez, mais n’est pas le meilleur moyen de transmission pour les applications autorisées avec perte de données.