Comment détecter une déconnexion de socket TCP (avec socket C Berkeley)

J’utilise une boucle pour lire le message d’un socket Berkeley, mais je ne parviens pas à détecter le moment où le socket est déconnecté. J’accepte donc une nouvelle connexion. s’il vous plaît aider

while(true) { bzero(buffer,256); n = read(newsockfd,buffer,255); printf("%s\n",buffer); } 

Le seul moyen de détecter la connexion d’un socket consiste à lui écrire.

Obtenir une erreur sur read()/recv() indiquera que la connexion est rompue, mais ne pas obtenir une erreur lors de la lecture ne signifie pas que la connexion est en place.

Vous pouvez être intéressé à lire ceci: http://lkml.indiana.edu/hypermail/linux/kernel/0106.1/1154.html

De plus, l’utilisation de TCP Keep Alive peut aider à distinguer les connexions inactives des connexions rompues (en envoyant quelque chose à intervalles réguliers, même s’il n’y a pas de données à envoyer par l’application).

(EDIT: Suppression de la phrase incorrecte comme l’a souligné @Damon, merci.)

Votre problème est que vous ignorez complètement le résultat renvoyé par read() . Votre code après read() devrait ressembler au moins à ceci:

 if (n == 0) // peer disconnected break; else if (n == -1) // error { perror("read"); break; } else // received 'n' bytes { printf("%.*s", n, buffer); } 

Et accepter une nouvelle connexion doit être fait dans un thread séparé, indépendant de la fin du stream de cette connexion.

L’appel bzero() est inutile, c’est une solution de contournement pour les erreurs précédentes.

C’est parce que vous n’avez pas utilisé le délai d’attente Keepalive. En réception, l’option de socket keepalive est la meilleure solution pour détecter les connexions inactives.

Mais, si votre application continue à écrire sur le socket, il y a quelque chose à penser plus. Même si vous avez déjà défini l’option keepalive sur votre socket d’application, vous ne pouvez pas détecter à temps l’état de connexion inactive du socket, car votre application continue d’écrire sur le socket. C’est à cause de la retransmission TCP par la stack TCP du kernel. tcp_resortinges1 et tcp_resortinges2 sont des parameters de kernel pour la configuration du délai d’attente de retransmission TCP. Il est difficile de prédire l’heure précise du délai d’attente de retransmission, car elle est calculée par le mécanisme RTT. Vous pouvez voir ce calcul dans RFC793. (3.7. Communication de données)

https://www.rfc-editor.org/rfc/rfc793.txt

Chaque plate-forme possède des configurations de kernel pour la retransmission TCP.

 Linux : tcp_resortinges1, tcp_resortinges2 : (exist in /proc/sys/net/ipv4) 

http://linux.die.net/man/7/tcp

 HPUX : tcp_ip_notify_interval, tcp_ip_abort_interval 

http://www.hpuxtips.es/?q=node/53

 AIX : rto_low, rto_high, rto_length, rto_limit 

http://www-903.ibm.com/kr/event/download/200804_324_swma/socket.pdf

Vous devez définir une valeur inférieure pour tcp_resortinges2 (valeur par défaut 15) si vous souhaitez détecter rapidement une connexion inactive, mais ce n’est pas l’heure précise, comme je l’ai déjà dit. De plus, vous ne pouvez actuellement pas définir ces valeurs pour un seul socket. Ce sont des parameters de kernel globaux. Il y a eu quelques essais pour appliquer l’option socket retransmission TCP pour un socket unique ( http://patchwork.ozlabs.org/patch/55236/ ), mais je ne pense pas que cela ait été appliqué à la ligne principale du kernel. Je ne trouve pas ces options dans les fichiers d’en-tête du système.

Pour référence, vous pouvez surveiller votre option de connexion keepalive via “netstat –timers” comme ci-dessous. https://stackoverflow.com/questions/34914278

 netstat -c --timer | grep "192.0.0.1:43245 192.0.68.1:49742" tcp 0 0 192.0.0.1:43245 192.0.68.1:49742 ESTABLISHED keepalive (1.92/0/0) tcp 0 0 192.0.0.1:43245 192.0.68.1:49742 ESTABLISHED keepalive (0.71/0/0) tcp 0 0 192.0.0.1:43245 192.0.68.1:49742 ESTABLISHED keepalive (9.46/0/1) tcp 0 0 192.0.0.1:43245 192.0.68.1:49742 ESTABLISHED keepalive (8.30/0/1) tcp 0 0 192.0.0.1:43245 192.0.68.1:49742 ESTABLISHED keepalive (7.14/0/1) tcp 0 0 192.0.0.1:43245 192.0.68.1:49742 ESTABLISHED keepalive (5.98/0/1) tcp 0 0 192.0.0.1:43245 192.0.68.1:49742 ESTABLISHED keepalive (4.82/0/1) 

En outre, lorsque le délai d’expiration keepalive survient, vous pouvez rencontrer différents événements de retour en fonction des plateformes que vous utilisez. Vous ne devez donc pas décider du statut de connexion morte uniquement par des événements de retour. Par exemple, HP renvoie l’événement POLLERR et AIX renvoie l’événement POLLIN uniquement lorsque le délai de conservation est dépassé. Vous rencontrerez l’erreur ETIMEDOUT dans l’appel recv () à ce moment.

Dans la version récente du kernel (depuis la version 2.6.37), vous pouvez utiliser l’option TCP_USER_TIMEOUT qui fonctionnera bien. Cette option peut être utilisée pour une seule prise.