Linux Socket: Comment détecter le réseau déconnecté dans un programme client?
Je suis le débogage d'un c linux basée sur les sockets. Comme tous les exemples disponibles dans les sites web,
J'ai appliqué la structure suivante:
sockfd= socket(AF_INET, SOCK_STREAM, 0);
connect(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr));
send_bytes = send(sockfd, sock_buff, (size_t)buff_bytes, MSG_DONTWAIT);
Je peux détecter la déconnexion lorsque le serveur de supprimer ferme son programme serveur. Mais si je débranchez le câble ethernet, la fonction d'envoi de toujours revenir à des valeurs positives plutôt que de -1.
Comment puis-je vérifier la connexion réseau dans un programme client en supposant que je ne peux pas changer de serveur?
OriginalL'auteur user2052197 | 2013-02-08
Vous devez vous connecter pour publier un commentaire.
Tout d'abord, vous devez savoir
send
ne fait pas envoyer quoi que ce soit, c'est juste une mémoire-fonction de copie/d'appel système. Elle copie les données de votre processus pour le noyau de quelque temps plus tard, le noyau va récupérer ces données et de les envoyer de l'autre côté après l'emballage en segments et les paquets. Doncsend
ne peut renvoyer une erreur si:Le point principal est que
send
ne pas envoyer quoi que ce soit et, par conséquent, son code de retour n'est pas tout vous dire sur les données de fait arriver de l'autre côté.Revenir à votre question, lorsque le protocole TCP envoie des données, il s'attend à un valide accusé de réception dans un délai raisonnable. Si elle n'est pas en obtenir un, il renvoie. Combien de fois est-il renvoyer ? Chaque pile TCP fait les choses différemment, mais la norme est d'utiliser l'exponentielle d'interruption. C'est, d'abord attendre 1 seconde, puis 2, puis 4 et ainsi de suite. Sur certains des piles ce processus peut prendre de quelques minutes.
Le point principal est que, dans le cas d'une interruption TCP va déclarer une connexion morts qu'après une très longue période de silence (sur Linux il fait quelque chose comme 15 tentatives - plus de 5 minutes).
Une façon de résoudre ce problème est de mettre en œuvre certaines mécanisme de reconnaissance dans votre application. Vous pouvez par exemple envoyer une demande au serveur "réponse dans les 5 secondes ou je vais déclarer ce lien mort" et puis
recv
avec un délai d'attente.OriginalL'auteur cnicutar
Pour détecter une distance de déconnexion, faire un
read()
Vérifier ce fil pour plus d'info:
Peut lire() sur une socket connecté retour à zéro octets?
OriginalL'auteur Forhad Ahmed
Vous ne pouvez pas détecter le débranché le câble ethernet uniquement avec l'appel write() funcation.
C'est à cause de retransmission tcp agi par pile tcp sans votre conscience.
Vous trouverez ici des solutions.
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.
Enfin, vous pouvez utiliser la fonction de lecture avec MSG_PEEK drapeau, qui peut vous permettre de vérifier que le support est correct. (MSG_PEEK simplement un oeil si les données sont arrivés au noyau de la mémoire tampon de la pile et ne copie jamais les données dans la mémoire tampon de l'utilisateur.)
Ainsi, vous pouvez utiliser ce drapeau juste pour la vérification de la socket est correct sans aucun effet secondaire.
OriginalL'auteur cloudrain21
Vérifier la valeur de retour, et voir s'il est égal à cette valeur:
Également d'ajouter une case pour le SIGNAL de signal de votre gestionnaire, de le rendre plus contrôlable.
OriginalL'auteur Ramy Al Zuhouri