Détection du TCP Client Disconnect

Disons que je lance un serveur simple et que accept() une connexion depuis un client.

Quelle est la meilleure façon de savoir quand le client est déconnecté? Normalement, un client est supposé 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 cela?

select (avec le masque de lecture défini) retournera avec le handle signalé, mais lorsque vous utilisez ioctl * pour vérifier le nombre d’octets en attente de lecture, il sera nul. Ceci est un signe que le socket a été déconnecté.

Ceci est une excellente discussion sur les différentes méthodes de vérification de la déconnexion du client: Stephen Cleary, Détection des connexions à moitié ouvertes .

* pour Windows, utilisez ioctlsocket.

Dans TCP, il n’existe qu’une seule façon de détecter une déconnexion ordonnée, c’est en obtenant zéro comme valeur de retour de read()/recv()/recvXXX() lors de la lecture.

Il existe également un seul moyen fiable de détecter une connexion interrompue: en lui écrivant. Après avoir écrit suffisamment sur une connexion rompue, TCP aura effectué suffisamment de tentatives et de délais d’attente pour savoir qu’il est endommagé et que, par la suite, write()/send()/sendXXX() renverra -1 avec une valeur errno/WSAGetLastError() d’ ECONNRESET, ou dans certains cas, la connexion a expiré. Notez que ce dernier est différent du «délai de connexion», qui peut se produire lors de la phase de connexion.

Vous devez également définir un délai de lecture raisonnable et supprimer les connexions qui échouent.

La réponse ici à propos de ioctl() et FIONREAD est un non-sens de la concurrence. Tout ce que vous faites est de vous dire combien d’octets sont actuellement dans le tampon de réception de socket, disponible pour être lu sans blocage. Si un client ne vous envoie rien pendant cinq minutes, cela ne constitue pas une déconnexion, mais cela fait que FIONREAD à zéro. Pas la même chose: même pas proche.

Pour développer cela un peu plus:

Si vous exécutez un serveur, vous devez soit utiliser TCP_KEEPALIVE pour surveiller les connexions client, soit faire quelque chose de similaire, soit connaître le protocole / les données que vous utilisez sur la connexion.

Fondamentalement, si la connexion est supprimée (c’est-à-dire pas correctement fermée), le serveur ne le remarquera pas tant qu’il n’aura pas essayé d’écrire quelque chose au client, ce que le keepalive réalise pour vous. Sinon, si vous connaissez mieux le protocole, vous pouvez simplement vous déconnecter en cas de délai d’inactivité.

Si vous utilisez des E / S superposées (c.-à-d. Asynchrones) avec des routines d’achèvement ou des ports d’achèvement, vous serez immédiatement averti (en supposant que vous ayez une lecture en attente) lorsque le client ferme la connexion.

 """ tcp_disconnect.py Echo network data test program in python. This easily translates to C & Java. A server program might want to confirm that a tcp client is still connected before it sends a data. That is, detect if its connected without reading from socket. This will demonstrate how to detect a TCP client disconnect without reading data. The method to do this: 1) select on socket as poll (no wait) 2) if no recv data waiting, then client still connected 3) if recv data waiting, the read one char using PEEK flag 4) if PEEK data len=0, then client has disconnected, otherwise its connected. Note, the peek flag will read data without removing it from tcp queue. To see it in action: 0) run this program on one computer 1) from another computer, connect via telnet port 12345, 2) type a line of data 3) wait to see it echo, 4) type another line, 5) disconnect quickly, 6) watch the program will detect the disconnect and exit. John Masinter, 17-Dec-2008 """ import socket import time import select HOST = '' # all local interfaces PORT = 12345 # port to listen # listen for new TCP connections s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) s.bind((HOST, PORT)) s.listen(1) # accept new conneciton conn, addr = s.accept() print 'Connected by', addr # loop reading/echoing, until client disconnects try: conn.send("Send me data, and I will echo it back after a short delay.\n") while 1: data = conn.recv(1024) # recv all data queued if not data: break # client disconnected time.sleep(3) # simulate time consuming work # below will detect if client disconnects during sleep r, w, e = select.select([conn], [], [], 0) # more data waiting? print "select: r=%sw=%se=%s" % (r,w,e) # debug output to command line if r: # yes, data avail to read. t = conn.recv(1024, socket.MSG_PEEK) # read without remove from queue print "peek: len=%d, data=%s" % (len(t),t) # debug output if len(t)==0: # length of data peeked 0? print "Client disconnected." # client disconnected break # quit program conn.send("-->"+data) # echo only if still connected finally: conn.close() 

Essayez de rechercher EPOLLHUP ou EPOLLERR. Comment puis-je vérifier que la connexion client est toujours active

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

TCP a des procédures “open” et “close” dans le protocole. Une fois “ouvert”, une connexion est maintenue jusqu’à “fermé”. Mais il y a beaucoup de choses qui peuvent arrêter le stream de données de manière anormale. Cela étant dit, les techniques permettant de déterminer s’il est possible d’utiliser un lien dépendent fortement des couches logicielles entre le protocole et le programme d’application. Celles mentionnées ci-dessus concernent un programmeur qui tente d’utiliser une socket de manière non invasive (lire ou écrire 0 octet) sont peut-être les plus courantes. Certaines couches de bibliothèques fourniront le “polling” pour un programmeur. Par exemple, les appels Win32 asych (différés) peuvent démarrer une lecture qui retournera sans erreur et 0 octet pour signaler un socket qui ne peut plus être lu (probablement une procédure TCP FIN). D’autres environnements peuvent utiliser des “événements” tels que définis dans leurs couches enveloppantes. Il n’y a pas de réponse unique à cette question. Le mécanisme permettant de détecter si un socket ne peut pas être utilisé et doit être fermé dépend des wrappers fournis dans les bibliothèques. Il est également intéressant de noter que les sockets eux-mêmes peuvent être réutilisés par des calques situés sous une bibliothèque d’applications. Il est donc judicieux de déterminer comment votre environnement gère l’interface Berkley Sockets.

La valeur de retour de recevoir sera -1 si la connexion est perdue sinon il s’agira de la taille du tampon.

 void ReceiveStream(void *threadid) { while(true) { while(ch==0) { char buffer[1024]; int newData; newData = recv(thisSocket, buffer, sizeof(buffer), 0); if(newData>=0) { std::cout << buffer << std::endl; } else { std::cout << "Client disconnected" << std::endl; if (thisSocket) { #ifdef WIN32 closesocket(thisSocket); WSACleanup(); #endif #ifdef LINUX close(thisSocket); #endif } break; } } ch = 1; StartSocket(); } } 

La bibliothèque apr du projet apache est une bonne référence pour ce problème. Il utilise poll avec une valeur de délai d’attente pour vérifier si l’autre connexion côté est cassé ou non.

J’ai joué avec quelques solutions mais celle-ci semble mieux fonctionner pour détecter la déconnexion de l’hôte et / ou du client sous Windows. Il est destiné aux sockets non bloquants et dérive de l’exemple d’ IBM .

 char buf; int length=recv(socket, &buf, 0, 0); int nError=WSAGetLastError(); if(nError!=WSAEWOULDBLOCK&&nError!=0){ return 0; } if (nError==0){ if (length==0) return 0; } 

C’est vraiment facile à faire: fiable et pas désordonné:

  Try Clients.Client.Send(BufferByte) Catch verror As Exception BufferSsortingng = verror.ToSsortingng End Try If BufferSsortingng <> "" Then EventLog.Text &= "User disconnected: " + vbNewLine Clients.Close() End If 

Nous avons rencontré le même problème lors de la détection du retrait du câble sur le PC. Après avoir googlé, nous avons trouvé la bibliothèque SuperCom for TCP qui offrait cette fonctionnalité et une bibliothèque de communication de données très fiable qui pouvait également gérer les événements de rapport lorsqu’une connexion était fermée.

Cette question est fondée sur diverses idées fausses concernant la stack réseau.

Tout d’abord, il n’y a pas de concept de «connexion» Tcp ou autre et plus tôt vous faites cette distinction, plus vite vous réaliserez que ce n’est pas différent de udp ou de tout autre protocole.

Lorsque vos délais de réception expirent, vous avez soit des données à envoyer, soit vous ne les avez pas.

Si vous ne voulez pas transmettre que, augmentez éventuellement le délai d’attente et recevez à nouveau.

Si le client a débranché l’ordinateur ou s’est déconnecté, comment ou pourquoi?

Est-ce que ça va casser votre «connexion»? Peut-être mais peut-être pas, qui sait comment votre machine est configurée ou le LSP de tel.

La manière normale de procéder est la même que pour tous les autres protocoles et je vous rappelle que le socket est déjà «connecté» dans les cas où un recive se produit.

Lorsque vous essayez d’envoyer à ce client quelque chose, vous saurez si le client est “connecté” ou plus correctement reconnu vos données sous Tcp. (Sous udp également en fonction du réseau via icmp)

Pourquoi vous avez voté cette réponse à cause de votre propre malentendu.

En bref, si vous avez des données à envoyer, envoyez-les et déterminez quelle action est nécessaire après l’envoi ou l’échec de l’envoi.

Si votre opération de réception arrive à expiration, vous pouvez utiliser un envoi de taille 0 pour confirmer que votre correspondant reçoit toujours vos données.