9
votes

Fermer sur la prise ne relâchant pas le descripteur de fichier

Lorsque vous effectuez un test de stress sur un code de serveur, j'ai écrit, j'ai remarqué que même si j'appelle Fermer () sur la poignée de descripteur (et vérifiant le résultat pour les erreurs) que le descripteur n'est pas publié, ce qui éventuellement active () Pour renvoyer une erreur "Trop de fichiers ouverts".

Maintenant, je comprends que c'est à cause de l'ulimit, ce que je ne comprends pas, c'est pourquoi je l'appelle si j'appelle Fermer () après chaque acceptation synchrone / lecture / Envoyer le cycle?

Je valide que les descripteurs sont en fait là en exécutant une montre avec lsof: xxx

et sûr, il y a environ 1000 ou donc d'eux. De plus, vérifiant avec NetStat, je peux voir qu'il n'y a pas d'états TCP suspendus (pas d'attente ou d'arrêt ou de rien).

Si je fais simplement une seule connexion / envoi / RECV du client, je remarque que la prise reste répertoriée dans LSOF; Donc, ce n'est même pas un problème de charge.

Le serveur s'exécute sur une machine Ubuntu Linux 64 bits.

Toute réflexion?


6 commentaires

En supposant tout ce que vous dites est vrai, cela ressemble à un bug de noyau. Un étroit succès doit absolument libérer le descripteur.


Appelez-vous Arrêter et / ou consommez toutes les données dans la prise avant de fermer les poignées de la prise? Avez-vous suspendu lire s ou écrire s lorsque vous appelez Fermer ?


Essayez d'utiliser la strace si les appels Connect / Envivez / Recv sont aussi étroitement couplés que vous le dites, il doit être assez clair de la sortie de diagnostic.


NetStat -Inet vous dira l'état des sessions TCP. S'ils sont "établis", vous n'avez pas appelé fermer () .


Publiez un code si vous souhaitez que nous aidions. Si vous êtes incapable de le faire, utilisez un profileur comme Valgrind pour suivre les descripteurs. Cela ressemble à un bug d'application pour moi.


Dans mon cas, c'était parce que les threads principaux et secondaires n'ont pas partagé la table descripteur de fichier (j'ai créé un thread séparé pour chaque connexion). Pour fixer soit Ajouter clone_files drapeau sur clone ou fermeture de fermeture dans le fil principal après avoir créé un fil secondaire (mais pas à la fois)


3 Réponses :


0
votes

Vous êtes très probablement suspendu à un recv () ou envoyer () . Envisagez de définir un délai d'attente en utilisant setSockopt .

J'ai remarqué une sortie similaire sur LSOF lorsque la prise a été fermée à l'autre extrémité, mais mon thread conserve la prise ouverte sur la commande RECV () En attente de données.


1 commentaires

Blocage dans RECV () ou Envoyer () n'empêche pas la fermeture de la prise ou de la libération de la FD. Votre deuxième paragraphe décrit une situation impossible. Si la pair fermait la connexion, votre RECV () aurait cessé de bloquer et de renvoyer une valeur de retour zéro. Vous avez eu un autre bug. -1



5
votes

Ainsi, en utilisant la strace (mercifroïde), ce que je n'ai aucune idée de ce que j'ai jamais vécu sans, j'ai noté que j'étais en train de fermer les descripteurs.

Cependant. Et pour l'amour de la postérité, je pose ma faute stupide: xxx

Comme vous pouvez le constater, mon constructeur a attribué un socket immédiatement, puis j'ai remplacé le descripteur avec celui qui est retourné. par accepter - créer une fuite. J'avais refoulé le code d'accepteur d'une classe d'accepteur autonome dans la classe Socket sans changer cela.

Utilisation de la strace, je pouvais facilement voir la prise () étant couru chaque fois que mène à mon ampoule.

Merci à tous pour l'aide!


0 commentaires

1
votes

Avez-vous déjà appelé Perror () après étroite ()? Je pense que la chaîne retournée vous donnera de l'aide;


0 commentaires