it-swarm.com.de

Erkennen TCP Client trennen

Nehmen wir an, ich betreibe einen einfachen Server und habe accept()ed eine Verbindung von einem Client aus.

Wie kann ich am besten feststellen, wenn der Client die Verbindung getrennt hat? Normalerweise soll ein Client einen Befehl zum Schließen senden, aber was ist, wenn er die Verbindung manuell getrennt oder die Netzwerkverbindung vollständig verliert? Wie kann der Server dies erkennen oder behandeln?

64
Zxaos

select (mit der Lesemaske) wird mit dem signalisierten Handle zurückgegeben. Wenn Sie jedoch mit ioctl * die Anzahl der zu lesenden Bytes überprüfen, ist diese Null. Dies ist ein Zeichen dafür, dass die Steckdose getrennt wurde.

Dies ist eine großartige Diskussion über die verschiedenen Methoden zum Überprüfen, ob der Client die Verbindung getrennt hat: Stephen Cleary, Erkennung von halb geöffneten (gelöschten) Verbindungen .

* Für Windows verwenden Sie ioctlsocket.

3
sep

In TCP gibt es nur eine Möglichkeit, eine ordnungsgemäße Unterbrechung der Verbindung zu erkennen, und zwar durch Abrufen von Null als Rückgabewert von read()/recv()/recvXXX() beim Lesen.

Es gibt auch nur einen zuverlässigen Weg, eine unterbrochene Verbindung zu erkennen: indem Sie darauf schreiben. Nachdem genügend Verbindungen zu einer unterbrochenen Verbindung geschrieben wurden, hat TCP genügend Wiederholungen und Zeitüberschreitungen ausgeführt, um zu wissen, dass die Verbindung unterbrochen wurde, und schließlich wird write()/send()/sendXXX() dazu veranlasst, -1 mit einem errno/WSAGetLastError()-Wert von ECONNRESET, oder in einigen Fällen 'Verbindungszeitüberschreitung' zurückzugeben. Beachten Sie, dass sich letzteres von 'connect timeout' unterscheidet, das in der Verbindungsphase auftreten kann.

Sie sollten auch ein angemessenes Lesezeitlimit festlegen und Verbindungen, bei denen dies fehlschlägt, trennen.

Die Antwort hier zu ioctl() und FIONREAD ist kompletter Unsinn. Sie müssen nur sagen, wie viele Bytes sich derzeit im Socket-Empfangspuffer befinden, sodass sie ohne Blockierung gelesen werden können. Wenn ein Client Ihnen fünf Minuten lang nichts sendet, stellt dies keine Trennung dar, verursacht jedoch, dass FIONREAD null ist. Nicht dasselbe: nicht einmal in der Nähe.

92
user207421

Um dies etwas weiter zu erläutern:

Wenn Sie einen Server betreiben, müssen Sie entweder TCP_KEEPALIVE verwenden, um die Clientverbindungen zu überwachen, oder etwas Ähnliches selbst ausführen, oder Sie wissen, welche Daten/Protokolle Sie über die Verbindung ausführen.

Wenn die Verbindung abgebrochen wird (d. H. Nicht ordnungsgemäß geschlossen wird), wird der Server grundsätzlich nichts bemerken, bis er versucht, dem Client etwas zu schreiben. Wenn Sie das Protokoll besser kennen, können Sie die Verbindung zu einem Inaktivitätszeitlimit trotzdem einfach trennen.

12
Peter Jeffery

Wenn Sie überlappende (d. H. Asynchrone) E/A mit Abschlussroutinen oder Abschlussports verwenden, werden Sie sofort benachrichtigt (vorausgesetzt, Sie haben ein ausstehendes Leseverhalten), wenn der Client die Verbindung beendet.

2
Graeme Perrow
"""
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
John Masinter

Suchen Sie nach EPOLLHUP oder EPOLLERR. Wie überprüfe ich, ob die Clientverbindung noch aktiv ist

Lesen und Suchen nach 0 funktioniert in einigen Fällen, jedoch nicht in allen.

0

Der Rückgabewert von receive wird -1 sein, wenn die Verbindung unterbrochen wird.

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
Anand Paul

TCP hat "offene" und "schließende" Prozeduren im Protokoll. Einmal "geöffnet" wird eine Verbindung gehalten, bis "geschlossen". Es gibt jedoch viele Dinge, die den Datenfluss anormal stören können. Die Techniken, mit denen festgestellt wird, ob eine Verbindung verwendet werden kann, hängen stark von den Softwareschichten zwischen dem Protokoll und dem Anwendungsprogramm ab. Die oben genannten konzentrieren sich auf einen Programmierer, der versucht, einen Socket auf nicht invasive Weise zu verwenden (Lesen oder Schreiben von 0 Bytes). Einige Schichten in Bibliotheken liefern die "Abfrage" für einen Programmierer. Win32-asych (verzögerte) Aufrufe können beispielsweise einen Lesevorgang starten, der ohne Fehler und 0 Byte zurückgibt, um einen nicht mehr lesbaren Socket zu signalisieren (vermutlich eine TCP FIN-Prozedur). In anderen Umgebungen werden möglicherweise "Ereignisse" verwendet, die in den Umbruchschichten definiert sind. Auf diese Frage gibt es keine Antwort. Der Mechanismus zum Erkennen, wann ein Socket nicht verwendet werden kann und geschlossen werden sollte, hängt von den in den Bibliotheken bereitgestellten Wrappern ab. Beachten Sie auch, dass Sockets selbst von Layern unterhalb einer Anwendungsbibliothek wiederverwendet werden können. Es ist daher ratsam, herauszufinden, wie Ihre Umgebung mit der Berkley Sockets-Schnittstelle umgehen soll.

0
jlpayton