118 votos

¿Cómo cerrar por la fuerza un enchufe en TIME_WAIT?

Ejecuto un programa particular en linux que a veces se bloquea. Si lo abres rápidamente después de eso, escucha en el zócalo 49201 en lugar de 49200 como lo hizo la primera vez. netstat revela que 49200 está en estado de TIME_WAIT.

¿Hay algún programa que pueda ejecutar para forzar inmediatamente a ese enchufe a salir del estado TIME_WAIT?

153voto

Jedi Master Spooky Puntos 2374
/etc/init.d/networking restart

Déjame explicarte. El Protocolo de Control de Transmisión (TCP) está diseñado para ser un protocolo de transmisión de datos bidireccional, ordenado y fiable entre dos puntos finales (programas). En este contexto, el término fiable significa que retransmitirá los paquetes si se pierde en el medio. TCP garantiza la fiabilidad enviando de vuelta los paquetes de Reconocimiento (ACK) para un solo paquete o un rango de paquetes recibidos del par.

Lo mismo ocurre con las señales de control como la solicitud/respuesta de terminación. RFC 793 define el estado TIME-WAIT de la siguiente manera:

TIME-WAIT - representa la espera de suficiente tiempo para pasar para estar seguro el TCP remoto recibió el reconocimiento de su conexión solicitud de terminación.

Véase el siguiente diagrama de estado del TCP: alt text

El TCP es un protocolo de comunicación bidireccional, por lo que cuando se establece la conexión, no hay diferencia entre el cliente y el servidor. Además, cualquiera de los dos puede llamar a la salida, y ambos compañeros necesitan acordar el cierre para cerrar completamente una conexión TCP establecida.

Llamemos al primero que se retira como el activo más cercano, y al otro como el pasivo más cercano. Cuando el cerrador activo envía FIN, el estado pasa a FIN-WAIT-1. Luego recibe un ACK para el FIN enviado y el estado pasa a FIN-WAIT-2. Una vez que recibe FIN también del cerrador pasivo, el cerrador activo envía el ACK a FIN y el estado pasa a TIME-WAIT. En caso de que el cerrador pasivo no haya recibido el ACK a la segunda FIN, retransmitirá el paquete FIN.

RFC 793 establece que el TIEMPO DE SALIDA es el doble de la vida útil del segmento máximo, o 2MSL. Desde el MSL, el tiempo máximo que un paquete puede deambular por Internet, se establece en 2 minutos, 2MSL es 4 minutos. Dado que no hay ACK a un ACK, el cerrador activo no puede hacer otra cosa que esperar 4 minutos si se adhiere correctamente al protocolo TCP/IP, por si acaso el emisor pasivo no ha recibido el ACK a su FIN (en teoría).

En realidad, los paquetes perdidos son probablemente raros, y muy raros si todo ocurre dentro de la LAN o dentro de una sola máquina.

Para responder a la pregunta literalmente, ¿Cómo a la fuerza cerrar un enchufe en TIME_WAIT?, seguiré manteniendo mi respuesta original:

/etc/init.d/networking restart

Prácticamente hablando, lo programaría para que ignore el estado TIME-WAIT usando la opción SO_REUSEADDR como mencionó WMR. ¿Qué hace exactamente SO_REUSEADDR?

Esta opción de enchufe le dice al núcleo que incluso si este puerto está ocupado (en
el estado TIME_WAIT), adelante y reutilizarlo de todos modos. Si está ocupado, pero con otro estado, aún así conseguirás un error de dirección ya en uso. Es es útil si su servidor ha sido cerrado y luego se reinició de inmediato mientras que los enchufes están todavía activos en su puerto. Debe ser consciente de que si cualquier dato inesperado que llegue, puede confundir a su servidor, pero mientras esto es posible, no es probable.

52voto

WMR Puntos 701

No sé si tienes el código fuente de ese programa en particular que estás ejecutando, pero si es así podrías establecer SO_REUSEADDR vía setsockopt(2) que le permite vincularse a la misma dirección local incluso si el socket está en estado TIME_WAIT (a menos que ese socket esté escuchando activamente, ver socket(7) ).

Para más información sobre el estado TIME_WAIT vea el Preguntas frecuentes sobre el enchufe de Unix .

34voto

Ben Hamill Puntos 655

Por lo que sé, no hay forma de cerrar a la fuerza el socket fuera de escribir un mejor manejador de señales en su programa, pero hay un archivo /proc que controla el tiempo de espera. El archivo es

/proc/sys/net/ipv4/tcp_tw_recycle

y puedes ajustar el tiempo de espera a 1 segundo haciendo esto:

echo 1 > /proc/sys/net/ipv4/tcp_tw_recycle

Sin embargo, esta página contiene una advertencia sobre posibles problemas de fiabilidad al establecer esta variable.

También hay un archivo relacionado

/proc/sys/net/ipv4/tcp_tw_reuse

que controla si los enchufes TIME_WAIT pueden ser reutilizados (presumiblemente sin ningún tiempo de espera).

Por cierto, la documentación del núcleo le advierte de que no cambie ninguno de estos valores sin "consejos o peticiones de expertos técnicos". Lo cual no es así.

El programa debe haber sido escrito para intentar una unión al puerto 49200 y luego incrementarlo en 1 si el puerto ya está en uso. Por lo tanto, si tienes el control del código fuente, podrías cambiar este comportamiento para esperar unos segundos e intentarlo de nuevo en el mismo puerto, en lugar de incrementarlo.

18voto

akostadinov Puntos 380

En realidad hay una manera de matar una conexión killcx . Afirman que funciona en cualquier estado de la conexión (que no he verificado). Necesitas saber la interfaz donde ocurre la comunicación, sin embargo, parece asumir el eth0 por defecto.

ACTUALIZACIÓN: otra solución es Cortador que viene en los depósitos de algunas distribuciones de Linux.

EnMiMaquinaFunciona.com

EnMiMaquinaFunciona es una comunidad de administradores de sistemas en la que puedes resolver tus problemas y dudas.
Puedes consultar las preguntas de otros sysadmin, hacer tus propias preguntas o resolver las de los demás.

Powered by: