Ejecuto un programa particular en Linux que a veces falla. Si lo abre rápidamente después de eso, escuchará en el socket 49201 en lugar de 49200 como lo hizo la primera vez. netstat revela que 49200 está en un estado TIME_WAIT.
¿Hay algún programa que pueda ejecutar para forzar de inmediato a ese socket a salir del estado TIME_WAIT?
TIME_WAIT
en el servidor" , omita las tres primeras respuestas que evitan la pregunta en lugar de responderla.Respuestas:
Déjame elaborar. El Protocolo de control de transmisión (TCP) está diseñado para ser un protocolo de transmisión de datos bidireccional, ordenado y confiable entre dos puntos finales (programas). En este contexto, el término confiable significa que retransmitirá los paquetes si se pierde en el medio. TCP garantiza la confiabilidad al devolver los paquetes de acuse de recibo (ACK) para un solo paquete o un rango de paquetes recibidos del par.
Esto es igual para las señales de control, como la solicitud / respuesta de terminación. RFC 793 define el estado de ESPERA DE TIEMPO como el siguiente:
Consulte el siguiente diagrama de estado TCP:
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 dejar de fumar y ambos pares deben acordar el cierre para cerrar completamente una conexión TCP establecida.
Llamemos al primero para llamar a los abandonos como el cerrador activo, y el otro mira al cerrador pasivo. Cuando el cerrador activo envía FIN, el estado pasa a FIN-WAIT-1. Luego recibe un ACK por 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 al FIN y el estado pasa a ESPERA DE TIEMPO. En caso de que el cerrador pasivo no haya recibido el ACK al segundo FIN, retransmitirá el paquete FIN.
RFC 793 establece que el TIEMPO DE ESPERA sea el doble de la vida útil máxima del segmento, o 2MSL. Dado que MSL, el tiempo máximo que un paquete puede deambular por Internet, se establece en 2 minutos, 2MSL es de 4 minutos. Como no hay ACK en un ACK, el cerrador activo no puede hacer nada más que esperar 4 minutos si se adhiere correctamente al protocolo TCP / IP, en caso de que el remitente pasivo no haya recibido el ACK en su FIN (en teoría) .
En realidad, los paquetes perdidos son probablemente raros, y muy raros si todo sucede dentro de la LAN o dentro de una sola máquina.
Para responder la pregunta al pie de la letra, ¿Cómo cerrar a la fuerza un socket en TIME_WAIT ?, aún me atendré a mi respuesta original:
Hablando prácticamente, lo programaría para que ignore el estado de ESPERA DE TIEMPO usando la opción SO_REUSEADDR como mencionó WMR. ¿Qué hace exactamente SO_REUSEADDR?
fuente
/etc/init.d/networking
es específica de la plataforma (¿Debian?), Por lo que la línea de comandos precisa será diferente (a veces bastante radical) para otros sistemas. Estoy de acuerdo con otros comentaristas en que esto parece una exageración severa y obviamente perjudicial para cualquier servicio de red no relacionado.No sé si tiene el código fuente de ese programa en particular que está ejecutando, pero si es así, puede configurar SO_REUSEADDR a través de lo
setsockopt(2)
cual le permite enlazar en la misma dirección local incluso si el socket está en estado TIME_WAIT (a menos que socket está escuchando activamente, versocket(7)
).Para obtener más información sobre el estado TIME_WAIT, consulte las preguntas frecuentes sobre el socket Unix .
fuente
SO_REUSEADDR
no "cierra" un socket. Simplemente le permite reutilizar los que ya están abiertos. Entonces la pregunta sigue siendo "¿Cómo cerrar a la fuerza un zócaloTIME_WAIT
?SO_REUSEADDR
dejarebind()
proceder; pero si luego quieres escuchar ese socket,listen()
te devolveráEADDRINUSE
lo mismo. En otras palabras, esta respuesta puede ayudar al software del cliente a usar puertos efímeros, pero no resuelve el problema del software del servidor.Hasta donde sé, no hay forma de cerrar el socket por la fuerza fuera de escribir un mejor controlador de señal en su programa, pero hay un archivo / proc que controla cuánto tiempo tarda el tiempo de espera. El archivo es
y puede establecer el tiempo de espera en 1 segundo haciendo esto:
Sin embargo, esta página contiene una advertencia sobre posibles problemas de confiabilidad al configurar esta variable.
También hay un archivo relacionado
que controla si los sockets TIME_WAIT se pueden reutilizar (presumiblemente sin ningún tiempo de espera).
Por cierto, la documentación del núcleo le advierte que no cambie ninguno de estos valores sin 'consejos / solicitudes de expertos técnicos'. Lo cual no soy.
El programa debe haberse escrito para intentar un enlace al puerto 49200 y luego incrementarlo en 1 si el puerto ya está en uso. Por lo tanto, si tiene el control del código fuente, puede cambiar este comportamiento para esperar unos segundos e intentar nuevamente en el mismo puerto, en lugar de aumentar.
fuente
1
funcione para conexiones futuras, pero ¿qué pasa con las actuales que ya están abiertas?En realidad, hay una manera de eliminar una conexión: killcx . Afirman que funciona en cualquier estado de la conexión (que no he verificado). Sin embargo, debe conocer la interfaz donde se produce la comunicación, parece asumir eth0 por defecto.
ACTUALIZACIÓN: otra solución es cutter que viene en algunos repositorios de distribuciones de Linux.
fuente
Otra opción es usar la opción SO_LINGER con un tiempo de espera de 0. De esta manera, cuando cierra el socket se cierra por la fuerza, se envía un RST en lugar de entrar en el comportamiento de cierre FIN / ACK. Esto evitará el estado TIME_WAIT y puede ser más apropiado para algunos usos.
fuente
Una solución alternativa sería tener un proxy confiable o un software de reenvío de puertos que escuche en el puerto 49200, luego reenvíe la conexión a una de varias instancias de su programa menos confiable usando diferentes puertos ... HAPROXY viene a la mente.
Por cierto, el puerto en el que se conecta es bastante alto. Puede intentar usar uno sin usar justo por encima del rango 0-1024. Es menos probable que su sistema use un número de puerto más bajo como un puerto efímero.
fuente
TIME_WAIT es el problema más común en la arquitectura del servidor del cliente de programación de sockets. Espere unos segundos, intentarlo periódicamente es la mejor solución para ello. Para las aplicaciones en tiempo real, necesitan que el servidor se levante de inmediato. Hay una opción SO_REUSEADDR para ellos.
fuente