Detectando la desconexión del cliente TCP

Digamos que estoy ejecutando un servidor simple y tengo accept() ed una conexión de un cliente.

¿Cuál es la mejor manera de saber cuándo el cliente se desconectó? Normalmente, se supone que un cliente envía un comando de cierre, pero ¿qué sucede si se desconecta manualmente o pierde la conexión de red por completo? ¿Cómo puede el servidor detectar o manejar esto?

    select (con el conjunto de máscara de lectura) volverá con el identificador señalado, pero cuando use ioctl * para verificar el número de bytes pendientes de lectura, será cero. Este es un signo de que el socket ha sido desconectado.

    Esta es una gran discusión sobre los diversos métodos para verificar que el cliente se haya desconectado: Stephen Cleary, detección de conexiones semiabiertas (descartadas) .

    * para Windows use ioctlsocket.

    En TCP solo hay una forma de detectar una desconexión ordenada, y es obtener cero como valor de retorno de read()/recv()/recvXXX() al leer.

    También hay una sola forma confiable de detectar una conexión interrumpida: escribiendo en ella. Después de escribir suficiente en una conexión interrumpida, TCP habrá hecho suficientes bashs y tiempos de espera para saber que está roto y eventualmente hará que write()/send()/sendXXX() devuelva -1 con un valor errno/WSAGetLastError() de ECONNRESET, o ECONNRESET, en algunos casos, “la conexión ha expirado”. Tenga en cuenta que este último es diferente de ‘connect timeout’, que puede ocurrir en la fase de conexión.

    También debe establecer un tiempo de espera de lectura razonable y descartar las conexiones que no lo logren.

    La respuesta aquí sobre ioctl() y FIONREAD tiene sentido. Todo lo que hace es decirle cuántos bytes hay actualmente en el búfer de recepción del zócalo, disponible para leer sin bloquear. Si un cliente no le envía nada durante cinco minutos, eso no constituye una desconexión, pero hace que FIONREAD sea ​​cero. No es lo mismo: ni siquiera cerca.

    Para ampliar esto un poco más:

    Si está ejecutando un servidor, necesita usar TCP_KEEPALIVE para monitorear las conexiones del cliente, o hacer algo similar usted mismo, o tener conocimiento sobre los datos / protocolo que está ejecutando sobre la conexión.

    Básicamente, si se mata la conexión (es decir, no se cierra correctamente), el servidor no se dará cuenta hasta que intente escribir algo al cliente, que es lo que logra el objective para ti. Alternativamente, si conoces mejor el protocolo, podrías desconectarte en un tiempo de inactividad de todos modos.

    Si usa E / S superpuestas (es decir, asincrónicas) con rutinas de finalización o puertos de finalización, se le notificará inmediatamente (suponiendo que tenga una lectura destacada) cuando el lado del cliente cierre la conexión.

     """ 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() 

    Intente buscar EPOLLHUP o EPOLLERR. Cómo verifico que la conexión del cliente todavía está viva

    Leer y buscar 0 funcionará en algunos casos, pero no en todos.

    TCP tiene procedimientos “abiertos” y “cercanos” en el protocolo. Una vez “abierto”, la conexión se mantiene hasta que se “cierra”. Pero hay muchas cosas que pueden detener el flujo de datos de forma anormal. Dicho esto, las técnicas para determinar si es posible utilizar un enlace dependen en gran medida de las capas de software entre el protocolo y el progtwig de aplicación. Los mencionados anteriormente se centran en un progtwigdor que intenta utilizar un socket de forma no invasiva (leer o escribir 0 bytes) es quizás el más común. Algunas capas de las bibliotecas suministrarán el “sondeo” para un progtwigdor. Por ejemplo, las llamadas asych (retardadas) de Win32 pueden iniciar una lectura que retornará sin errores y 0 bytes para señalar un socket que ya no se puede leer (presumiblemente un procedimiento TCP FIN). Otros entornos pueden usar “eventos” como se define en sus capas de envoltura. No hay una respuesta única a esta pregunta. El mecanismo para detectar cuándo un socket no puede usarse y debe cerrarse depende de los envoltorios que se proporcionan en las bibliotecas. También vale la pena señalar que los sockets en sí mismos se pueden reutilizar por capas debajo de una biblioteca de aplicaciones, por lo que es aconsejable averiguar cómo su entorno se relaciona con la interfaz de Berkley Sockets.

    El valor de retorno de receive será -1 si se pierde la conexión, de lo contrario será el tamaño del buffer.

     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 biblioteca apr del proyecto Apache es una buena referencia para este problema. Utiliza encuesta con un valor de tiempo de espera para verificar si la otra conexión lateral está rota o no.

    Jugué con algunas soluciones, pero esta parece funcionar mejor para detectar la desconexión de host y / o cliente en Windows. Es para sockets no bloqueantes, y se deriva del ejemplo de 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; } 

    Es realmente fácil de hacer: confiable y no desordenado:

      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 

    Nos encontramos con un problema similar cuando detectamos la eliminación del cable en la PC. Después de buscar en Google, accedimos a la biblioteca de SuperCom para TCP que ofrecía esta característica y una biblioteca de comunicación de datos muy confiable que también podía manejar eventos de informes cuando se cerraba una conexión.

    Esta pregunta se basa en varios conceptos erróneos sobre la stack de red.

    En primer lugar, no existe el concepto de una “conexión” Tcp o de otra manera, y cuanto antes se haga esa distinción, antes se dará cuenta de que no es diferente de udp o de cualquier otro protocolo.

    Cuando su tiempo de espera se agote, o bien tiene datos para enviar o no los tiene.

    Si no quiere transmitir, opcionalmente aumente el tiempo de espera y vuelva a recibir.

    Si el cliente desconectó la computadora o se desconectó de otra manera, ¿cómo o por qué importa eso?

    ¿Eso va a romper tu ‘conexión’? Tal vez, pero tal vez no, quién sabe cómo está configurada su máquina o el LSP de los mismos.

    La forma normal de hacer esto es como con cualquier otro protocolo y le recuerdo que el socket ya está ‘conectado’ en los casos en que ocurre una recepción.

    Cuando intente enviar algo a ese cliente, sabrá si el cliente está “conectado” o si sus datos están más correctamente acreditados en Tcp. (Bajo udp también dependiendo de la red a través de icmp)

    Por qué votaste esa respuesta es por tu propio malentendido.

    En resumen, si tiene datos para enviar, envíelos y determine qué acción se requiere después de enviarlos con éxito o fallidos.

    Si la operación de recepción se agota, se aplica lo mismo y, opcionalmente, puede usar un envío de tamaño 0 para confirmar que la otra parte sigue recibiendo sus datos.