¿Cuál es el significado de SO_REUSEADDR (opción setsockopt) – Linux?

Desde la página man:

SO_REUSEADDR Especifica que las reglas utilizadas para validar las direcciones suministradas a bind () deberían permitir la reutilización de las direcciones locales, si esto es compatible con el protocolo. Esta opción toma un valor int. Esta es una opción booleana

¿Cuándo debería usarlo? ¿Por qué la “reutilización de direcciones locales” da?

El objective principal del diseño de TCP es permitir una comunicación de datos confiable frente a la pérdida de paquetes, el reordenamiento de paquetes y, clave, aquí, la duplicación de paquetes.

Es bastante obvio cómo una stack de red TCP / IP se ocupa de todo esto mientras la conexión está activa, pero hay un caso extremo que ocurre justo después de que se cierra la conexión. ¿Qué sucede si un paquete enviado justo al final de la conversación está duplicado y retrasado, de modo que los paquetes de apagado de 4 vías llegan al receptor antes del paquete retrasado? La stack cierra diligentemente su conexión. Luego, más tarde, aparece el paquete duplicado retrasado. ¿Qué debería hacer la stack?

Más importante aún, ¿qué debería hacer si el progtwig que poseía esa conexión muere inmediatamente, y luego otro comienza a querer la misma dirección IP y el mismo número de puerto TCP?

Hay un par de opciones:

  1. No permita la reutilización de ese combo IP / puerto por lo menos 2 veces el tiempo máximo que un paquete puede estar en vuelo. En TCP, esto generalmente se llama retraso 2 × MSL . A veces también ves 2 × RTT , que es más o menos equivalente.

    Este es el comportamiento predeterminado de todas las stacks TCP / IP comunes. 2 × MSL es típicamente entre 30 y 120 segundos. (Este es el período TIME_WAIT ). Después de ese tiempo, la stack asume que cualquier paquete fraudulento se ha eliminado en el camino debido a TTL caducados, por lo que deja el estado TIME_WAIT , lo que permite que se reutilice ese IP / puerto combinado.

  2. Permita que el nuevo progtwig vuelva a unirse a ese IP / combo de puerto. En las stacks con interfaces de sockets BSD , esencialmente todos los sistemas Unix y similares a Unix, más Windows a través de Winsock , debe solicitar este comportamiento estableciendo la opción SO_REUSEADDR través de setsockopt() antes de llamar a bind() .

SO_REUSEADDR se configura generalmente en progtwigs de servidor.

La razón es que un patrón común es que cambie un archivo de configuración del servidor y necesite reiniciarlo para que vuelva a cargar su configuración. Sin SO_REUSEADDR , la llamada bind() en la nueva instancia del progtwig reiniciado fallará si hubiera conexiones abiertas a la instancia anterior cuando la eliminó. Esas conexiones mantendrán el puerto TCP en el estado TIME_WAIT durante 30-120 segundos, por lo que se cae en el caso 1 anterior.

Lo más seguro es esperar el período TIME_WAIT , pero en la práctica no es un riesgo lo suficientemente grande como para que valga la pena hacerlo. Es mejor hacer una copia de seguridad del servidor inmediatamente para no perder más conexiones entrantes de las necesarias.

SO_REUSEADDR permite que su servidor se vincule con una dirección que está en un
Estado de TIME_WAIT.

Esta opción de socket le dice al kernel que incluso si este puerto está ocupado (en el estado TIME_WAIT), adelante y reutilícelo de todos modos. Si está ocupado, pero con otro estado, aún recibirá una dirección que ya está en uso. Es útil si su servidor se ha apagado y luego se ha reiniciado de inmediato mientras los sockets todavía están activos en su puerto.

De unixguide.net

Cuando creas un socket, realmente no lo tienes. El sistema operativo (stack TCP) lo crea para usted y le proporciona un identificador (descriptor de archivo) para acceder a él. Cuando el socket está cerrado, lleva tiempo que el sistema operativo “lo cierre completamente” mientras atraviesa varios estados. Como EJP mencionó en los comentarios, la demora más larga suele ser del estado TIME_WAIT. Se requiere este retraso adicional para manejar las cajas de borde al final de la secuencia de finalización y asegurarse de que la última confirmación de terminación haya finalizado o que el otro lado se haya reiniciado debido a un tiempo de espera excedido. Aquí puede encontrar algunas consideraciones adicionales sobre este estado. Las principales consideraciones se señalan a continuación:

Recuerde que TCP garantiza que se entregarán todos los datos transmitidos, si es posible. Cuando cierra un socket, el servidor entra en un estado TIME_WAIT, solo para estar realmente seguro de que se han procesado todos los datos. Cuando se cierra un socket, ambas partes acuerdan enviándose mensajes de que no enviarán más datos. Esto, me pareció que era lo suficientemente bueno, y después de que se haya hecho el apretón de manos, el socket debería estar cerrado. El problema es doble. En primer lugar, no hay forma de estar seguro de que el último ack se comunicó con éxito. Segundo, puede haber “duplicados errantes” en la red que deben ser tratados si se entregan.

Si intentas crear varios sockets con el mismo par de ip: puerto realmente rápido, obtienes el error de “dirección que ya está en uso” porque el socket anterior no se habrá liberado por completo. El uso de SO_REUSEADDR eliminará este error, ya que anulará las comprobaciones de cualquier instancia anterior.