Évitez de réutiliser le même numéro fd dans une application socket multithread

J’ai une application asynchrone exécutant plusieurs threads effectuant des opérations sur des sockets où les opérations sont planifiées puis exécutées de manière asynchrone.

J’essaie d’éviter une situation lorsqu’une fois programmé une opération de lecture sur un socket, le socket est fermé et rouvert (par un autre pair éventuellement dans une autre opération), avant que la première opération ne commence, ce qui finira par lire le descripteur de fichier approprié mais le mauvais pair.

Le problème vient du fait que (accept (); close (); accept ()) renvoie le même fd dans les deux accept (), ce qui peut conduire à la situation ci-dessus.

Je ne peux pas voir un moyen de l’éviter.

n’importe quel indice?

Ok, a trouvé la réponse.

Le meilleur moyen ici est d’appeler accept () et d’obtenir le fd le plus bas disponible, le dupliquer avec un numéro que vous connaissez comme dup2 (6,1000) et close (6), vous avez maintenant le contrôle de la plage fd que vous utilisez.

La prochaine acceptation reviendra avec 6 ou similaire, et nous allons dup2 (6 999); et continuez à diminuer comme cela et à le réinitialiser si cela devient trop faible.

Puisque l’acceptation se fait toujours dans le même thread et que dup2 et close ne sont pas chers par rapport à accepter qui se fait toujours là, c’est parfait pour mes besoins.

Comment gérez-vous les sockets? Il semblerait que vous ayez plusieurs threads dont:

  1. accept une connexion entrante
  2. close une connexion existante
  3. établir une nouvelle connexion sortante

Il semble que vous ayez besoin d’un moyen de médiation pour accéder aux différentes sockets qui circulent. Avez-vous envisagé d’associer chaque socket à mutex, ce qui empêche de fermer le socket tant qu’il est encore utilisé ou de placer chaque descripteur de socket dans une structure avec un compteur de références atomiques qui empêchera les autres threads de le fermer?

un socket est un 5-tuple {local-addr, local-addr, remote-addr, remote-port, proto}, donc si vous pouvez utiliser ces propriétés au lieu de fd pour le routage des événements / gestionnaires, vous pouvez éviter le conflit fd .

une autre option serait de sérialiser toutes les opérations close () / accept () (priorités?) afin qu’elles ne puissent pas se mélanger

Bonne question! Je n’ai même pas réalisé qu’un tel problème pouvait survenir.

La seule réponse à laquelle je puisse penser est que vous ne devez pas utiliser close () pour indiquer qu’une socket est terminée. Une solution consiste à utiliser shutdown () pour mettre fin à la connexion. Vous pouvez ensuite fermer () le socket en toute sécurité en utilisant le comptage de référence.

Je ferais quand même attention à utiliser dup2 () à une valeur bien connue de fd. Rappelez-vous que dup2 () effectuera une fermeture sur la cible avant de les doubler; cela pourrait entrer en conflit avec des threads non liés effectuant des E / S sans lien si vous commencez à avoir 1000 fichiers ouverts.

Si j’étais vous, compte tenu des contraintes sur lesquelles vous insistez, j’utiliserais dup () (et non dup2 ()) dans un mutex. (Peut-être que les mutex par fd si vous êtes concerné.)

Conservez le nombre d’opérations en attente (lecture / écriture, etc.) pour chaque socket et indiquez également s’il existe une demande de fermeture en attente sur le socket. Où avant vous auriez appelé close, vérifiez d’abord s’il y a des opérations en attente. Si c’est le cas, appelez plutôt shutdown, puis appelez seulement close lorsque le nombre d’opérations en attente atteint 0.