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.

-1voto

"""
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 votes

Vérifier que le socket est prêt mais n'a pas de données fonctionne très bien pour mon projet. Il s'agit d'une solution simple

3 votes

@luc Cela ne fonctionne pas du tout. C'est une solution simple, incorrecte et invalide. C'est un test pour la quantité de données qui peuvent être lues sans bloquer, pas un test pour une déconnexion. Vous devez lire pour tester cela. Si un client ne vous envoie rien pendant cinq minutes, FIONREAD sera égal à zéro, mais il est peut-être encore connecté.

1 votes

C'est Python mais l'étiquette indique C++.

-2voto

arsane Points 6500

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

-3voto

C'est très 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

0 votes

Ce n'est pas fiable. Elle ne fait pas la distinction entre les fermetures ordonnées et désordonnées, et ne fonctionne même pas avant qu'au moins deux envois aient eu lieu, à cause du tampon d'envoi de la socket.

-3voto

pgmonthego Points 1

Nous avons rencontré un problème similaire en détectant que le retrait du câble sur le PC était le problème. Après avoir cherché sur Internet, nous sommes tombés sur 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.

-4voto

Galleon Points 1

J'ai essayé plusieurs solutions, mais celle-ci semble être la plus efficace pour détecter la déconnexion de l'hôte et/ou du client sous Windows. Elle est pour les sockets non-bloquants, et dérivée 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;
}

0 votes

Un recv() ne fait rien sur le fil, il ne peut donc pas déclencher de détection de tirage de câble, etc. Seul un send() peut le faire.

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