Détection de la déconnexion du Client TCP

disons que j'exécute un serveur simple et que accept() a une connexion à partir d'un client.

Quelle est la meilleure façon de savoir quand le client a déconnecté? Normalement, un client est censé envoyer une commande close, mais qu'en est-il s'il se déconnecte manuellement ou perd la connexion réseau? Comment le serveur peut-il détecter ou gérer cela?

64
demandé sur Zxaos 2008-11-12 12:02:47

13 réponses

select (with the read mask set) va revenir avec la poignée signalée, mais quand vous utilisez ioctl* pour vérifier le nombre d'octets en attente d'être lus, il sera zéro. C'est un signe que la prise a été déconnectée.

il s'agit d'une excellente discussion sur les différentes méthodes de vérification que le client a déconnecté: Stephen Cleary, détection de connexions à moitié ouvertes (abandonnées) .

* pour Windows utilisez ioctlsocket.

3
répondu sep 2015-07-30 15:42:31

dans 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 read()/recv()/recvXXX() lors de la lecture.

il n'y a qu'un seul moyen fiable de détecter une connexion rompue: en lui écrivant. Après avoir écrit assez à une connexion cassée, TCP aura fait assez de tentatives et de timeouts pour savoir qu'elle est cassée et fera éventuellement revenir write()/send()/sendXXX() -1 avec une valeur errno/WSAGetLastError() de ECONNRESET, ou dans certains cas la "connection timed out". Notez que ce dernier est différent de 'connect timeout', qui peut se produire dans la phase de connexion.

vous devriez également définir un délai raisonnable de lecture, et les connexions de chute qui échouent.

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

87
répondu user207421 2013-12-07 08:54:28

Pour développer un peu plus:

si vous utilisez un serveur, vous devez soit utiliser TCP_KEEPALIVE pour surveiller les connexions du client, ou faire quelque chose de similaire vous-même, ou avoir connaissance des données/Protocole que vous utilisez sur la connexion.

en gros, si la connexion est désactivée (c'est-à-dire qu'elle n'est pas correctement fermée), le serveur ne remarquera rien tant qu'il n'essaiera pas d'écrire quelque chose au client, ce que le keepalive obtient pour vous. Par ailleurs, si vous connaissez mieux le protocole, vous pouvez vous déconnecter sur un temps d'inactivité de toute façon.

12
répondu Peter Jeffery 2008-11-12 11:41:12

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 avisé immédiatement (en supposant que vous avez une lecture en suspens) lorsque le côté client ferme la connexion.

2
répondu Graeme Perrow 2008-11-12 11:49:04
"""
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=%s w=%s e=%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()
0
répondu 2009-04-27 17:12:03

Try looking for EPOLLHUP or EPOLLERR. Comment puis-je vérifier que la connexion client est toujours vivante

lire et chercher 0 fonctionne dans certains cas, mais pas tous.

0
répondu Trade-Ideas Philip 2017-05-23 11:33:17

TCP a des procédures" ouvertes "et" fermées " dans le protocole. Une fois" ouverte", une connexion est maintenue jusqu'à"fermée". Mais il ya beaucoup de choses qui peuvent arrêter le flux de données anormalement. Cela étant dit, les techniques pour déterminer s'il est possible d'utiliser un lien sont très dépendantes des couches logicielles entre le protocole et le programme d'application. Ceux mentionnés ci-dessus se concentrent sur un programmeur essayant d'utiliser une socket d'une manière non invasive (lire ou écrire 0 bytes) sont peut-être le plus commun. Certains calques dans les bibliothèques fourniront le" polling " pour un programmeur. Par exemple, les appels Win32 asych (retardés) peuvent démarrer une lecture qui reviendra sans erreur et 0 octets pour signaler une socket qui ne peut plus être lue (probablement une procédure TCP FIN). D'autres environnements peuvent utiliser des "événements" tels que définis dans leurs couches d'enrubannage. Il n'y a pas de réponse unique à cette question. Le mécanisme pour détecter quand une socket ne peut pas être utilisé et doit être fermé dépend des enveloppes fourni dans les bibliothèques. Il est également intéressant de noter que les sockets eux-mêmes peuvent être réutilisés par des couches sous une bibliothèque d'applications, il est donc sage de comprendre comment votre environnement traite L'interface des Sockets de Berkley.

0
répondu jlpayton 2016-07-19 06:51:31

la valeur de retour de receive sera -1 si la connexion est perdue sinon ce sera 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();
    }
}
0
répondu Anand Paul 2017-10-05 09:12:35
La bibliothèque

apr du projet apache est une bonne référence pour ce problème. Il utilise poll avec une valeur de timeout pour vérifier si la connexion de l'autre côté est cassée ou non.

-2
répondu Sam Liao 2009-12-07 09:30:16

j'ai essayé quelques solutions mais celle-ci semble fonctionner le mieux pour détecter la déconnexion de l'hôte et/ou du client dans Windows. Il est pour les sockets non-bloquants, et dérivé de 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;
}
-2
répondu Galleon 2013-07-16 01:12:57

Il est vraiment facile à faire: fiable et pas salissant:

        Try
            Clients.Client.Send(BufferByte)
        Catch verror As Exception
            BufferString = verror.ToString
        End Try
        If BufferString <> "" Then
            EventLog.Text &= "User disconnected: " + vbNewLine
            Clients.Close()
        End If
-3
répondu user207421 2013-07-15 22:45:10

nous exécutons dans la même question lors de la détection du retrait du câble sur le PC était le problème. Après googling, nous avons cliqué sur la bibliothèque SuperCom pour 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 quand une connexion était fermée.

-3
répondu pgmonthego 2014-07-27 08:36:15

cette question Est fondée sur diverses idées fausses au sujet de la pile réseau.

tout d'abord, il n'y a pas de concept de 'connexion' Tcp ou autre et plus tôt vous ferez cette distinction plus tôt vous vous rendrez compte que ce n'est pas différent de udp ou de tout autre protocole.

lorsque votre temps de réception hors soit vous avez des données à envoyer ou vous ne le faites pas.

Si vous ne voulez pas transmettre que, éventuellement augmenter le délai d'attente et recevoir de nouveau.

Si le client débranché de l'ordinateur ou autrement déconnecté alors comment ou pourquoi cette question?

Est-ce que va briser votre "connexion"? Peut-être, mais peut-être pas, qui sait comment votre machine est mise en place ou le LSP de tels.

la façon normale de faire ceci est exactement comme avec tous les autres protocoles et je vous rappelle que la socket est déjà 'connectée' dans les cas où une recive se produit.

quand vous essayez d'Envoyer à ce client quelque chose que 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)

la raison pour laquelle vous avez voté cette réponse est à cause de votre propre malentendu.

en bref, si vous avez des données pour envoyer l'envoyer et de déterminer quelle action est nécessaire après l'envoi réussi ou échoué.

si votre temps d'opération de réception la même chose s'applique et vous pouvez éventuellement utiliser une taille 0 Envoyer pour confirmer que l'autre partie reçoit toujours vos données.

-7
répondu Jay 2015-03-18 19:09:15