Comment détecter un socket TCP déconnexion (avec C Berkeley socket)
Je suis l'aide d'une boucle pour lire le message d'un c Berkeley socket mais je ne suis pas en mesure de détecter si la socket est déconnecté, donc je accepter une nouvelle connexion. s'il vous plaît aider
while(true) {
bzero(buffer,256);
n = read(newsockfd,buffer,255);
printf("%s\n",buffer);
}
OriginalL'auteur Ayoub M. | 2011-06-19
Vous devez vous connecter pour publier un commentaire.
La seule façon vous pouvez détecter qu'une socket est connecté est par l'écriture.
Une erreur sur
read()/recv()
indique que la connexion est interrompue, mais de ne pas avoir une erreur lors de la lecture ne veut pas dire que la connexion est en place.Vous pouvez être intéressé par la lecture de ceci:
http://lkml.indiana.edu/hypermail/linux/kernel/0106.1/1154.html
En outre, l'utilisation de TCP Keep Alive peut aider à distinguer entre les inactifs et les connexions rompues (par l'envoi de quelque chose, à intervalles réguliers, même si il n'y a pas de données envoyées par l'application).
(EDIT: Suppression de la phrase incorrecte comme l'a souligné @Damon, merci.)
il n'y a pas de différence entre ne pas obtenir quoi que ce soit car rien n'a été envoyée et ne pas obtenir quoi que ce soit parce que le lien est rompu. (C'est un principe général en fait. Si vous n'obtenez pas de lettre dans la matinée, soit personne n'a envoyé quoi que ce soit vous ou le système postal ne fonctionne pas: vous ne pouvez savoir ce qui est la cause en essayant d'envoyer quelque chose par la poste, plus ou moins.) C'est pourquoi vous avez besoin pour gérer les délais d'attente lors de l'utilisation de connexions TCP. Une connexion qui est fermé brusquement sera tout simplement pas vous envoyer quelque chose à vous dire sa fermeture, car il ne peut pas.
bien sûr, il peut y avoir un délai, mais c'est la seule façon de détecter une déconnexion, encore. Vider la mémoire tampon si vous avez besoin de savoir dès que possible. (Si vous êtes en attente d'erreur de lecture, vous pouvez attendre un très long moment... et qui ne serait pas fiable.)
c'est une déconnexion brutale, à l'aide de l'écrire aussi sans défense, à droite?" Non, il n'est pas impuissant, il devrait fail, d'où vous pouvez détecter une déconnexion. Votre idée de s'attendant à recevoir une pulsation toutes les 15 sec est différent, il ya peut-être un plus long retard, sans la connexion à fermer. Vous êtes alors prendre une décision arbitraire quant à ce retard vous trouvez acceptable, c'est tout (et c'est souvent la bonne chose à faire pratiquement), mais qui n'a pas vraiment vous dire si la prise est débranchée, il signifie simplement que vous donnez et de l'assumer.
oui, brusque en ce sens (complète perte de paquets sans avertissement). Lorsque rien n'est destiné à être envoyé, vous ne pouvez pas savoir si vous êtes faits pour recevoir quelque chose (d'où l'idée de hearbeat dans le protocole comme vous l'avez suggéré, pour que les protocoles de soutien). La seule façon de savoir si elle est déconnectée est d'essayer d'écrire. Essayer de lire quelque chose si vous ne savez pas si c'est censé avoir envoyé quelque chose ne vous dira rien de toute façon. Votre cas est différent puisque vous êtes en utilisant un async écrire. Je ne sais pas de coup de pouce.asio très bien, mais essayez de vider la mémoire tampon immédiatement si vous le pouvez.
OriginalL'auteur Bruno
Votre problème est que vous êtes complètement ignorant le résultat retourné par
read()
. Votre code aprèsread()
devriez regarder moins comme ceci:Et d'accepter une nouvelle connexion doit être fait dans un thread séparé, ne dépend pas de la fin du flux sur cette connexion.
La
bzero()
appel est inutile, juste une solution de contournement pour avant les erreurs.OriginalL'auteur user207421
C'est parce que vous n'avez pas utiliser keepalive délai d'attente.
À côté de réception, keepalive option de socket est la meilleure solution pour la détection de la mort de la connexion.
Mais, dans le cas de votre demande de continuer à écrire à la prise, il ya quelque chose à penser plus.
Même si vous avez déjà mis en option persistantes à votre demande de support, vous ne pouvez pas les détecter à temps les morts d'état de la connexion de la prise, dans le cas de votre application garde d'écriture sur le support.
C'est à cause de retransmission tcp par le noyau de la pile tcp.
tcp_retries1 et tcp_retries2 sont les paramètres du noyau pour la configuration de tcp délai de retransmission.
Il est difficile de prévoir le moment précis du délai de retransmission, car il est calculé par la RTT mécanisme.
Vous pouvez voir ce calcul dans la rfc 793. (3.7. La Communication De Données)
https://www.rfc-editor.org/rfc/rfc793.txt
Chaque plates-formes ont des configurations de retransmission tcp.
http://linux.die.net/man/7/tcp
http://www.hpuxtips.es/?q=node/53
http://www-903.ibm.com/kr/event/download/200804_324_swma/socket.pdf
Vous devriez mettre en valeur plus faible pour tcp_retries2 (15 par défaut) si vous voulez de la détection précoce de connexion morte, mais ce n'est pas de temps précis, comme je l'ai déjà dit.
En outre, actuellement, vous ne pouvez pas définir ces valeurs uniquement pour une seule prise. Ceux sont globaux les paramètres du noyau.
Il y avait quelques essais à appliquer de retransmission tcp socket option pour une seule prise(http://patchwork.ozlabs.org/patch/55236/), mais je ne pense pas qu'il a été appliqué dans le noyau de la ligne principale. Je ne peux pas trouver ces options de définition dans le système de fichiers d'en-tête.
Pour référence, vous pouvez surveiller votre keepalive option de socket par "netstat --de la vieille" comme ci-dessous.
https://stackoverflow.com/questions/34914278
En outre, lorsque la directive keepalive délai d'attente apparaît, vous pouvez rencontrer divers événements selon les plateformes que vous utilisez, ainsi, vous ne devez pas décider de la mort d'état de la connexion uniquement par retour événements.
Par exemple, HP retourne POLLERR événement et AIX retourne juste POLLIN événement lors de keepalive délai d'attente se produit.
Vous rencontrerez ETIMEDOUT erreur dans recv() appel à cette époque.
Dans les dernières version du noyau(depuis 2.6.37), vous pouvez utiliser TCP_USER_TIMEOUT option fonctionne bien. Cette option peut être utilisée pour une seule prise.
reD()
.OriginalL'auteur cloudrain21