Comment puis-je me réveille select() sur une socket?
Je suis actuellement en utilisant sélectionnez boucle pour gérer les supports d'une procuration. L'une des exigences de la présente procuration est que si le proxy envoie un message à l'extérieur de serveur et ne pas obtenir une réponse dans un certain temps, le proxy doit fermer le socket et essayez de vous connecter à un serveur secondaire. La fermeture se fait dans un thread séparé, tandis que l'sélectionnez thread se bloque en attente pour l'activité.
J'ai de la difficulté à trouver comment détecter que cette prise fermé spécifiquement, de sorte que je peux gérer l'échec. Si je l'appelle close() dans l'autre thread, je reçois un EBADF, mais je ne peux pas dire qui socket fermée. J'ai essayé de détecter le support par le biais de l'exception fdset, pensant qu'il allait contenir le socket fermée, mais je ne suis pas d'obtenir quoi que ce soit restitués. J'ai aussi entendu l'appel de l'arrêt() envoie une FIN pour le serveur et de recevoir un AILERON arrière, de sorte que je peux la fermer; mais le point est moi qui essayais de fermer ce résultat n'obtenez pas de réponse dans le délai, donc je ne peux pas faire, que ce soit.
Si mes suppositions sont fausses, faites le moi savoir. Toutes les idées seront les bienvenues.
EDIT:
En réponse aux suggestions sur l'utilisation de sélectionner le temps: j'ai besoin de faire la clôture de manière asynchrone, parce que le client qui se connecte au proxy du temps et je ne peux pas attendre autour pour le sélectionner pour être interrogés. Cela ne fonctionne que si j'ai le temps très petit, ce qui pourrait ensuite être constamment interrogation et le gaspillage des ressources que je ne veux pas.
OriginalL'auteur Doldrim | 2009-08-25
Vous devez vous connecter pour publier un commentaire.
Généralement je viens de marquer la prise de clôture dans l'autre thread, et puis quand sélectionnez() renvoie la valeur de l'activité ou de l'expiration, je lance un nettoyage de passer et de fermer toutes les connexions mortes et mise à jour de la fd_set. Faire d'une autre manière vous ouvre à des conditions de course où vous avez donné sur la connexion, tout comme select() enfin reconnu certains de données, puis de le fermer, mais de l'autre thread essaie de traiter les données qui a été détecté et qui s'énerve pour trouver la fermeture de la connexion.
Oh, et poll() est généralement supérieure à sélectionner() en termes de ne pas avoir à copier autant de données autour de.
OriginalL'auteur woolstar
Vous ne pouvez pas libérer une ressource dans un thread tandis qu'un autre thread ou peut-être l'utiliser. L'appel de
close
sur un socket qui peuvent être utilisés dans un autre thread ne sera jamais droit. Il y aura toujours potentiellement désastreuses conditions de course.Il y a deux bonnes solutions à votre problème:
Ont le thread qui appelle
select
toujours utiliser un délai ne dépassant pas le plus long que vous êtes prêt à attendre pour traiter un délai d'attente. Lorsqu'un délai d'attente se produit, indiquent que certains endroit le thread qui appelleselect
remarquerez quand il revient d'select
. Ont ce thread ne le réelclose
de la prise dans l'entre-deux appels àselect
.Avoir le fil qui détecte le délai d'appel
shutdown
sur le socket. Ce sera la cause deselect
de retour, et alors que le thread ne leclose
.OriginalL'auteur David Schwartz
Comment faire face à EBADF sur select():
Ce code suppose que vous disposez d'un tableau de structures de clientèle qui ont "fd" les membres du descripteur de socket. La fonction fcntl() vérifie si le socket est toujours "en vie", et si non, nous faisons ce que nous avons à supprimer les morts socket et son client associé info.
OriginalL'auteur Warren Young
Il est difficile de commenter quand il voit qu'une petite partie de l'éléphant, mais peut-être que vous avez plus de compliquer les choses?
Je suppose que vous avez une certaine structure pour garder une trace de chaque socket et son info (comme le temps de recevoir une réponse). Vous pouvez modifier le select() de la boucle à utiliser un timeout. À l'intérieur il vérifier si il est temps de fermer le socket. Faire ce que vous devez faire pour la fermer et ne pas ajouter à la fd définit la prochaine fois.
OriginalL'auteur Duck
Si vous utilisez poll(2) comme suggéré dans d'autres réponses, vous pouvez utiliser le POLLNVAL état, qui est essentiellement EBADF, mais sur un fichier par fichier de descripteur de base, non pas sur l'ensemble du système d'appel que pour les sélectionner(2).
OriginalL'auteur camh
Utiliser un délai d'attente pour la sélectionner, et si la lecture ou l'écriture prêt/a-séquences d'erreur sont toutes vides (w.r.t socket), vérifier si elle a été fermée.
OriginalL'auteur shikhar
Il suffit de lancer un "test, sélectionnez" sur chaque support qui pourrait avoir fermé avec un zéro délai d'attente et de vérifier les résultats select et errno, jusqu'à trouver celui qui a fermé.
Le morceau suivant du code de démonstration démarre les deux sockets serveur sur des threads séparés et crée deux sockets client à se connecter à un serveur de socket. Puis il commence un autre thread, qui tuent au hasard l'un des sockets client au bout de 10 secondes (il suffit de le fermer). De clôture, soit le socket client causes sélectionnez échouer avec l'erreur dans le thread principal et le code ci-dessous va maintenant tester lequel des deux sockets a fermé.
Exemple de sortie pour l'exécution de ce test de code à deux reprises:
Toutefois, si votre système prend en charge
poll()
, je vous conseille fortement d'envisager l'utilisation de cette API au lieu deselect()
. Select est assez moche, héritage de l'API à partir du passé, de gauche là pour assurer la compatibilité avec le code existant. Sondage a une bien meilleure interface pour cette tâche, et il a un indicateur supplémentaire pour directement vous signaler qu'une socket est fermé localement:POLLNVAL
sera mis surrevents
si cette prise a été fermé, peu importe qui les drapeaux que vous avez demandée sur les événements, depuisPOLLNVAL
est une sortie de drapeaux, ce qui signifie qu'il est ignoré lorsqu'il est installé surevents
. Si le support n'a pas été fermé localement mais le serveur distant a juste fermé la connexion, le drapeauPOLLHUP
sera mis enrevents
(également une sortie de drapeau). Un autre avantage de sondage, c'est que le délai d'attente est tout simplement une valeur int (millisecondes, à grain fin assez pour de vrai réseau de prises de courant) et qu'il n'existe pas de limites pour le nombre de prises qui peuvent être suivis ou que leur valeur numérique de la gamme.socket
après laclose
mais avant de vous appelerselect
et obtenir le même descripteur.exemple, un autre thread pourrait appeler socket...", alors ne faites pas un autre thread le faire. C'est votre application, vous pouvez contrôler qui peut créer des sockets, où et quand.
La raison que j'ai écrit "Pour l'exemple" est parce que c'est juste une façon dont il peut aller mal. Il y a d'autres façons. Par exemple, une nouvelle version de la bibliothèque que vous avez été en utilisant pouvez maintenant créer un thread d'arrière-plan qui appelle
socket
et tout à coup votre code des pauses lorsque quelqu'un de mises à jour de la bibliothèque.OriginalL'auteur Mecki