102 votes

Détection de la déconnexion d'un client TCP

Disons que je fais tourner un serveur simple et que j'ai accept() ed une connexion d'un client.

Quelle est la meilleure façon de savoir si le client s'est déconnecté ? Normalement, un client est censé envoyer une commande de fermeture, mais que se passe-t-il s'il se déconnecte manuellement ou perd complètement la connexion réseau ? Comment le serveur peut-il détecter ou gérer cette situation ?

0 votes

Regardez ici (pour les pires scénarios) : tldp.org/HOWTO/TCP-Keepalive-HOWTO/overview.html (Vérification des pairs morts)

5 votes

Parce qu'il y a tellement de réponses fausses et trompeuses, voici la bonne réponse : Suivez les spécifications du protocole que vous implémentez au-dessus de TCP. Il doit préciser si cela se fait par des délais d'attente, des échecs d'écriture ou tout autre mécanisme. Si vous concevez un protocole, assurez-vous de concevoir un moyen de détecter la déconnexion du client, si cela est nécessaire.

157voto

EJP Points 113412

En TCP, il n'y a qu'une seule façon de détecter une déconnexion ordonnée, et c'est en obtenant zéro comme valeur de retour de la fonction read()/recv()/recvXXX() en lisant.

Il n'existe également qu'un seul moyen fiable de détecter une connexion interrompue : en écrivant sur celle-ci. Après un nombre suffisant d'écritures sur une connexion rompue, TCP aura effectué suffisamment de tentatives et de délais d'attente pour savoir qu'elle est rompue et finira par causer des problèmes de sécurité. write()/send()/sendXXX() pour retourner -1 avec un errno/WSAGetLastError() valeur de ECONNRESET, ou, dans certains cas, "la connexion a expiré". Notez que ce dernier cas est différent du "connect timeout", qui peut se produire pendant la phase de connexion.

Vous devez également fixer un délai de lecture raisonnable et supprimer les connexions qui ne le respectent pas.

La réponse ici sur ioctl() y FIONREAD est une absurdité compétitive. Tout ce que cela fait, c'est vous dire combien d'octets sont actuellement dans le tampon de réception de la socket, disponibles pour être lus sans blocage. Si un client ne vous envoie rien pendant cinq minutes, il ne s'agit pas d'une déconnexion, mais d'un blocage. FIONREAD à zéro. Ce n'est pas la même chose : c'est loin d'être le cas.

0 votes

Il convient de noter que la réinitialisation peut également se produire dans certaines conditions normales et ne signifie pas nécessairement que l'autre partie n'écoute plus. Il convient également de noter que le fait que la réception soit interrompue ne signifie pas non plus que l'autre partie n'écoute plus.

3 votes

Jay La question porte sur la manière de détecter les déconnexions TCP, et non sur les causes des réinitialisations de connexion. Il existe de nombreuses causes de "réinitialisation de la connexion" et je ne pense pas qu'aucune d'entre elles constitue un "fonctionnement normal". Il s'agit d'une condition anormale par définition.

0 votes

Seulement si vous considérez que sortir du service wifi est anormal... ou un excès de bruit de signal, des collisions de données ou autre exemple normal.

16voto

Peter Jeffery Points 166

Pour développer ce point un peu plus :

Si vous exécutez un serveur, vous devez soit utiliser TCP_KEEPALIVE pour surveiller les connexions des clients, soit faire quelque chose de similaire vous-même, soit avoir des connaissances sur les données/le protocole que vous exécutez sur la connexion.

En gros, si la connexion est tuée (c'est-à-dire qu'elle n'est pas correctement fermée), le serveur ne s'en rendra compte que lorsqu'il essaiera d'écrire quelque chose au client, ce que le keepalive fait pour vous. Alternativement, si vous connaissez mieux le protocole, vous pouvez simplement vous déconnecter sur un délai d'inactivité de toute façon.

0 votes

Le serveur doit également fixer un délai de lecture raisonnable et abandonner les connexions qui ne le respectent pas.

0 votes

Laisser tomber la connexion qui l'échoue ? Que se passe-t-il si le délai d'attente est conforme à la recommandation par défaut de 200 msec ? Ne devrait-il pas revenir à un certain délai raisonnable ? Peut-être cela entraînera-t-il trop de changement de contexte pour vous ? Toujours abandonner une connexion lorsque le tel Timeout est si faible n'est pas un bon conseil...

0 votes

Sur Winsock2, keepalive est interrogé toutes les 5 secondes et j'ai un appel bloquant send ou recv, alors keepalive fonctionnera-t-il correctement ? De plus, quelles sont les limites minimales pour le timeout et l'intervalle de keepalive ?

2voto

Graeme Perrow Points 22249

Si vous utilisez des E/S superposées (c'est-à-dire asynchrones) avec des routines de complétion ou des ports de complétion, vous serez immédiatement notifié (en supposant que vous ayez une lecture en cours) lorsque le côté client ferme la connexion.

0 votes

Pas tout à fait. Vous serez notifié dès que vous aurez lu jusqu'à la fin du flux. Cela pourrait prendre un temps fini s'il y avait des données importantes en vol depuis le client avant la fermeture.

2voto

Essayez de chercher EPOLLHUP ou EPOLLERR. Comment puis-je vérifier que la connexion du client est toujours en vie ?

La lecture et la recherche de 0 fonctionneront dans certains cas, mais pas dans tous.

0voto

jlpayton Points 9

Le protocole TCP comporte des procédures d'"ouverture" et de "fermeture". Une fois "ouverte", une connexion est maintenue jusqu'à sa "fermeture". Mais il y a beaucoup de choses qui peuvent arrêter le flux de données de façon anormale. Cela dit, les techniques permettant de déterminer s'il est possible d'utiliser une liaison dépendent fortement des couches logicielles situées entre le protocole et le programme d'application. Celles mentionnées ci-dessus, axées sur un programmeur tentant d'utiliser un socket de manière non invasive (lire ou écrire 0 octet), sont peut-être les plus courantes. Certaines couches dans les bibliothèques fourniront le "polling" pour un programmeur. Par exemple, les appels Win32 asych (retardés) peuvent lancer une lecture qui reviendra sans erreur et 0 octet pour signaler une socket qui ne peut plus être lue (vraisemblablement une procédure TCP FIN). D'autres environnements pourraient utiliser des "événements" tels que définis dans leurs couches d'habillage. Il n'y a pas de réponse unique à cette question. Le mécanisme pour détecter quand une socket ne peut plus être utilisée et doit être fermée dépend des wrappers fournis dans les bibliothèques. Il convient également de noter que les sockets eux-mêmes peuvent être réutilisés par des couches inférieures à une bibliothèque d'applications. Il est donc judicieux de déterminer comment votre environnement traite l'interface Berkley Sockets.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X