7
votes

Socket reste ouvert après la fermeture du programme (C ++)

J'écris actuellement une petite application de serveur, et mon problème est que lorsque je ferme mon application (ou mieux, appuyez sur le bouton Terminate de Eclipse), la prise reste parfois ouverte, alors quand j'exécute mon application le prochain Le temps, lier () échouera avec «adresse déjà utilisée». Comment puis-je fermer correctement mes sockets lorsque le programme sort? J'ai déjà mis

close(mySocket);


2 commentaires

Êtes-vous sûr que les destructeurs fonctionnent? Pouvez-vous mettre une certaine production ou un point d'arrêt pour voir?


TCP est normalisé "sur le fil" mais pas au niveau de l'API. Par conséquent, l'une des choses les plus importantes lors de la poser des questions concernant TCP est de divulguer la plate-forme.


6 Réponses :


-1
votes

Êtes-vous sûr que votre application ne fonctionne pas toujours en arrière-plan?


5 commentaires

Oui, à peu près. Kill -9 devrait certainement le fermer, n'est-ce pas? Quoi qu'il en soit, je ne peux pas le trouver quand je grep sur ps -a.


Kill -9 devrait s'en occuper. C'est surprenant.


Sauf que Kill -9 signifie "fermer cette chose maintenant", pas "Dites à cette chose de se fermer correctement". Il ne appellera pas des destructeurs.


Peut-être que vous pouvez écrire un gestionnaire de signal pour terminer toutes vos connexions ouvertes si une CTRL-C ou une autre condition se produit.


Kill -9 n'appellera pas les dtors, mais sur [la plupart] Unix, l'arrêt du processus ferme les descripteurs de fichiers ouverts, qui ferme les sockets.



5
votes

2
votes

Avez-vous défini l'option SO_REUSeADDRDRDRDRDRDRTR? D'après ce que vous dites, cela ne semble pas.


0 commentaires

3
votes

http://hea-www.harvard.edu/~fine /Tech/addrinuse.html devrait répondre à beaucoup de vos questions. J'ai tendance à utiliser So_reouseaddr pour contourner ce problème.


5 commentaires

OK, si je comprends bien, ce type d'ignore que la prise est toujours rapportée comme utilisée. Mais y a-t-il un moyen de le fermer correctement en premier lieu?


Oui mais où. Où devrais-je appeler cela pour l'obtenir exécuté lorsque mon application se terminait.


Appeler fermer () ne pourra pas nécessairement éviter l'adresse déjà utilisée. Si le noyau ne récupère pas le ACK de l'ailette que vous avez envoyée en appelant à proximité avant la fin du processus, la prise liée ira dans time_wait, et vous devrez attendre quelques minutes avant que le noyau ne décide que cela ne gagne probablement pas ' t être réutilisé. Réglage SO_REUSEADDRDR permettra au noyau de réutiliser immédiatement cette adresse.


TIME_WAIT n'a rien à voir avec si l'extrême face envoie un ack. Voir le diagramme de transition d'état à userPages.umbc.edu/~jeehye/ CMSC491B / Lectures / TCPState / ... et l'explication de l'état Time_Wait dans ma réponse ci-dessous.


Pour répondre où vous devriez l'appeler. Vous devez attraper le signal SIGTERM (le signal envoyé pour mettre fin à un processus avant de recourir à un sigkille) et peut-être le signal SIGINT, et appelez fermer () dans le gestionnaire pour ce signal.



4
votes

Utilisez netstat pour déterminer quel état votre point final est dans. Je suppose que c'est que c'est dans temps_wait et non complètement fermé. C'est un comportement correct pour TCP et il existe pour permettre aux segments errants qui pourraient toujours être dans l'éther d'arriver et de ne pas causer de problèmes. La durée du time_wait est quelque chose comme 2 * msl, c'est-à-dire la durée maximale de la durée maximale d'un segment du réseau, assurant ainsi que même un segment qui devient retransmis est correctement manipulé.

Comme d'autres ont souligné, SO_REUSeADDRDRDRDRR est votre ami aussi longtemps que le point final de l'extrême face est différent à chaque fois. C'est l'affaire commune, mais parfois les gens font des choses étranges comme lier un client à un port spécifique et, dans ce cas, vous vous retrouverez toujours avec un Eaddrinuse B / C TCP définit une session comme Les deux points d'extrémité.


0 commentaires

0
votes

N'oubliez pas de vérifier la valeur de retour de la fermeture. Il retournera 0 lorsque la prise est fermée avec succès. Il retournera -1 s'il a échoué.


0 commentaires