Terminación de una conexión TCP

Terminación de una conexión TCP

de Facundo Padula Lenna -
Número de respuestas: 5

Investigamos y leímos que para detectar si un socket se cerró debemos utilizar recv y send. El primero devuelve 0 en el caso que el socket se haya cerrado y el otro -1 con la bandera SIGPIPE encedida. En el caso de que el cliente cierre la conexión, lo chequeamos en el servidor (que no recibimos datos) verificando el resultado del send para decidir si cerrar el socket o no.

Seǵun los paquetes que vemos en el Wireshark, cuando el cliente cierra la conexión con un close(), se manda el segmento FINACK del cliente al servidor, el ACK del servidor al cliente, y luego el servidor manda un frame al cliente, que responde con RST (especificando que no hay un socket para ese segmento), y nunca se finaliza la secuencia de las dos parejas FIN-ACK restantes. Creemos que es porque intentamos hacer un send() a un socket cerrado, pero no vemos otra forma de detectar que se haya cerrado. ¿Es aceptable este fin de la conexión?

También vimos que al cerrar "abruptamente" (con Ctrl+C) el servidor, se mandan las dos parejas FIN-ACK como corresponde, y en ese caso no ejecutamos ningún close, lo que nos hace pensar que el sistema se encarga de eso.

Todo esto nos genera las siguientes dudas a nivel de capa de transporte:

¿Ejecutar un close() significa mandar el segmento FIN que da inicio a la finalización? ¿Del lado que recibo el FIN, tengo que específicamente ejecutar otro close() para mandar el par restante de FIN-ACK? ¿O esto se ejecuta en la capa de transporte fuera de nuestro alcance?

¿Si no se ejecuta el close() y se cierra el programa, el FIN se envían igual? ¿Quién lo envía?

Agradecemos si nos despejan estas dudas, gracias.

En respuesta a Facundo Padula Lenna

Re: Terminación de una conexión TCP

de Matias Richart -

Hola Facundo.

Cerrar un socket TCP correctamente es complicado en algunos casos.

El problema que están teniendo es por eso mismo que decís, por intentar hacer un send en un socket que el cliente ya cerró.

Eso porque el servidor antes de cerrar intenta enviar todo lo pendiente. En la tabla de esta página se explica bastante bien los estados por los que pasa un socket antes de cerrar: http://www.tcpipguide.com/free/t_TCPConnectionTermination-2.htm

Nuestro caso es un poco complicado porque es un servidor "raro", que solo envía y no recibe nada.

La solución que yo sugiero para hacer un cierre correcto es agregar al servidor un recv no bloqueante. Este recv cuando no hay nada para recibir retorna -1 y cuando el socket está cerrado retorna 0.

Es interesante ver como cuando el recv retorna 0, es decir el socket esta "cerrando", el send igual permite enviar.

>¿Ejecutar un close() significa mandar el segmento FIN que da inicio a la finalización?

Si.

>¿Del lado que recibo el FIN, tengo que específicamente ejecutar otro close() para mandar el par restante de FIN-ACK?

Si.

>¿Si no se ejecuta el close() y se cierra el programa, el FIN se envían igual? ¿Quién lo envía?

No lo se. Esto depende de que hace tu programa con la señal SIGINT que recibe cuando haces Ctrl+C.


Espero haber aclarado.

Saludos


En respuesta a Matias Richart

Re: Terminación de una conexión TCP

de German Ernesto Larrosa Fiori -

Hola, cuando la aplicacion se cierra de manera no usual (ctrl+c) lo que hacemos es capturar esa interrumpcion (usando la libreria  zmq) y hacemos close(socket), entedemos que de esta manera los sockets no deberian quedar "colgados".

saludos.

En respuesta a Matias Richart

Re: Terminación de una conexión TCP

de Lia Colombo Scaramelli -

Está bien usar la herramienta netstat para fijarnos si los sockets se cerraron bien? o hay alguna forma mejor?


Gracias!

En respuesta a Lia Colombo Scaramelli

Re: Terminación de una conexión TCP

de Leonardo Vidal -

Si está bien o no depende de si les brinda la información que necesitan. Si se las brinda, está bien.

En cuanto al comando en sí mismo, ahora hay una tendencia a usar más el comando ss en lugar del netstat; algo parecido a dig y nslookup para DNS...

Slds.

En respuesta a Matias Richart

Re: Terminación de una conexión TCP

de Damian Augusto Langone Fusari -

Buenas,


En python tenemos el problema de que si utilizamos un recv no bloqueante para verificar que el socket esta cerrado, y efectivamente esta cerrado, en vez de retornar -1 o 0, nos tira una excepcion. Entonces nos obliga a tener que colocar el codigo de  envio del frame dentro de la excepcion. La pregunta que tenemos es si colocar codigo de ese estilo en una interrupcion esta correcto o se ve mal.


Gracias, saludos