En Linux (mis servidores en vivo están en RHEL 5.5; los enlaces LXR a continuación corresponden a la versión del kernel), man 7 ip
dice:
Una dirección de socket local TCP que se ha vinculado no estará disponible durante algún tiempo después del cierre, a menos que se haya establecido el indicador SO_REUSEADDR.
No estoy usando SO_REUSEADDR
. ¿Cuánto dura "algún tiempo"? ¿Cómo puedo saber cuánto dura y cómo puedo cambiarlo?
He estado buscando en esto, y he encontrado algunos bocados de información, ninguno de los cuales realmente explica esto desde la perspectiva de un programador de aplicaciones. Esto es:
- TCP_TIMEWAIT_LEN en
net/tcp.h
es "cuánto tiempo esperar para destruir el estado TIME-WAIT", y se fija en "aproximadamente 60 segundos" - / proc / sys / net / ipv4 / tcp_fin_timeout es "Hora de mantener el socket en el estado FIN-WAIT-2, si fue cerrado por nuestro lado", y "El valor predeterminado es 60 segundos"
Donde me tropiezo es para cerrar la brecha entre el modelo del núcleo del ciclo de vida TCP y el modelo de puertos del programador que no están disponibles, es decir, para comprender cómo estos estados se relacionan con "algún tiempo".
man 2 bind
si no me crees. Es cierto que probablemente no es lo primero que piensan las personas de Unix cuando alguien dice "atar", por lo que es bastante justo.bind
, pero la etiqueta aquí se aplica específicamente al servidor DNS. No tenemos etiquetas para cada posible llamada al sistema.Respuestas:
Creo que la idea de que el socket no esté disponible para un programa es permitir que lleguen los segmentos de datos TCP aún en tránsito y que el núcleo los descarte. Es decir, es posible que una aplicación llame
close(2)
a un zócalo, pero los retrasos en el enrutamiento o los percances para controlar los paquetes o lo que tenga puede permitir que el otro lado de una conexión TCP envíe datos por un tiempo. La aplicación ha indicado que ya no quiere tratar con segmentos de datos TCP, por lo que el núcleo debería descartarlos a medida que entran.He pirateado un pequeño programa en C que puedes compilar y usar para ver cuánto dura el tiempo de espera:
Probé este programa en 3 máquinas diferentes, y obtengo un tiempo variable, entre 55 y 59 segundos, cuando el núcleo se niega a permitir que un usuario no root vuelva a abrir un socket. Compilé el código anterior en un ejecutable llamado "abridor", y lo ejecuté así:
Abrí otra ventana e hice esto:
Eso hace que la primera instancia de "abridor" acepte una conexión y luego la cierre. La segunda instancia de "abridor" intenta al
bind(2)
puerto TCP 7896 cada segundo. "abridor" reporta 55 a 59 segundos de retraso.Buscando en Google, encuentro que la gente recomienda hacer esto:
para reducir ese intervalo. No me funcionó. De las 4 máquinas Linux a las que tenía acceso, dos tenían 30 y dos tenían 60. También establecí ese valor tan bajo como 10. No hay diferencia con el programa "abridor".
Haciendo esto:
Cambió las cosas. El segundo "abridor" solo tardó unos 3 segundos en obtener su nuevo zócalo.
fuente