Question

Espérons que quelqu'un peut nous aider comme nous atteindre aussi loin que l'enquête peut aller!

Nous avons un simple serveur socket asynchrone écrit en C # qui accepte les connexions à partir d'une application Web ASP.NET, est envoyé un message, effectue un traitement (habituellement contre un DB, mais d'autres systèmes aussi) et envoie une réponse en retour au client. Le client est responsable de la fermeture de la connexion.

Nous avons eu des questions où si le système est sous une lourde charge sur une longue période de temps (jours habituellement), prises CLOSE_WAIT construire sur la zone de serveur (netstat) dans une certaine mesure que le processus n'acceptera d'autres connexions. À ce moment-là, nous devons rebondir le processus et hors il fonctionne à nouveau.

Nous avons essayé l'exécution de certains tests de charge de notre application ASP.NET pour tenter de reproduire le problème (parce inférant une question du code n'a pas été possible). Nous pensons que nous avons réussi cela et a fini avec un WireShark trace paquet de la question qui se manifeste comme dans SocketException les logs du serveur de socket:

  

System.Net.Sockets.SocketException: a dû être fermée une connexion existante par l'hôte distant   à System.Net.Sockets.Socket.BeginSend (tampon byte [], Int32 offset, taille Int32, SocketFlags SocketFlags, AsyncCallback rappel, l'état de l'objet)

J'ai essayé de reproduire le problème de la trace de paquet comme un processus mono-thread parle directement au serveur socket (en utilisant le même code l'application ASP.NET ne) et je suis incapable.

Quelqu'un at-il eu des suggestions de choses à venir essayer, vérifier les choses évidentes ou nous pouvons faire mal?

Était-ce utile?

La solution

Regardez le diagramme

http://en.wikipedia.org/wiki/File:Tcp_state_diagram_fixed.svg

Votre client a fermé la connexion en appelant close (), qui a envoyé FIN à la prise du serveur, qui ACKed la FIN et dont l'état changé à CLOSE_WAIT, et reste ainsi à moins que les problèmes de serveur close () appelez ce socket.

Votre programme a besoin de serveur pour détecter si le client a annulé la connexion, puis fermez () immédiatement pour libérer le port. Comment? Reportez-vous à lire (). À la lecture de fin de fichier (ce qui signifie FIN est reçu), zéro est renvoyé.

Autres conseils

Si votre serveur accumule les sockets CLOSE_WAIT il est ne pas fermer sa prise lorsque la connexion est terminée. Si vous jetez un coup d'oeil au diagramme d'état dans le commentaire au poste de Chris, vous verrez que les transitions de CLOSE_WAIT à LAST_ACK une fois que la prise est fermée et le FIN a été envoyé.

Vous dites qu'il est complexe de déterminer où le faire en raison de la nature async? Cela ne devrait pas être un problème, vous devez fermer la prise si le rappel de votre recv retourne 0 octets (en supposant que vous avez rien d'autre à faire une fois que votre client ferme son côté de la connexion). Si vous avez besoin de vous soucier de continuer à envoyer ensuite faire un arrêt (RECV) ici et notez que votre client a fermé, une fois que vous avez terminé l'envoi d'exécuter un arrêt (envoyer) et Fermer.

Vous pouvez être émission d'une nouvelle lecture dans le rappel de la lecture qui retourne 0 indiquant que le client a fermé et cela peut vous causer des problèmes?

  

Le client est responsable de la fermeture de la connexion.

Le client et le serveur doit fermer et l'arrêt de la prise. Soit le client ne termine la fin (peu probable - car il faudrait il est géré finaliseur) ou le serveur n'arrête la prise (probable)

.
using (Socket s = new Socket(/* */)) {
  /* Do stuff */
  s.Shutdown(SocketShutdown.Both);
  s.Close();
}

Vous ne devriez pas laisser la responsabilité de fermer les sockets TCP uniquement au client. Qu'advient-il si le processus client / machine tombe en panne?

Idéalement, vous devriez avoir un délai d'attente en place afin que si aucun trafic est reçue sur une socket connectée après un certain laps de temps, alors il se ferme par le serveur.

Peu importe ce qui se passe lorsque toutes les opérations sur la prise a terminé par le client, et il n'a pas besoin de faire des opérations plus lues sur la prise, le client doit émettre une commande de fermeture.

Cette émission de commande de fermeture, indique simplement l'auditeur (le serveur) que la connexion doit être arrêté.

En mots simples, lorsque le serveur émet à nouveau une commande de lecture (listener.read () ou listener.beginread (...) en mode asynchrone), la lecture retourne un 0 octets lus, ce qui en soi indique que la socket doit être fermé par l'auditeur comme toutes les autres opérations sur la douille a cessé par le client.

de CLOSE_WAIT sont destinés à traîner pendant un certain temps après une prise est fermée, pour éviter de réutiliser le même numéro de socket et recevoir des paquets de l'ancienne connexion. Cela ne vous donnera du chagrin si vous ouvrir et fermer un certain nombre huuuuge de prises très rapidement.

EDIT -. Il devrait être TIME_WAIT, pas Close_Wait ci-dessus

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top