Para mi sugerencia, lea la última sección: "Cuándo usar SO_LINGER con timeout 0" .
Antes de llegar a eso, una pequeña conferencia sobre:
- Terminación TCP normal
TIME_WAIT
FIN, ACKyRST
Terminación TCP normal
La secuencia de terminación de TCP normal se ve así (simplificada):
Tenemos dos pares: A y B
- A llama
close()
- A envía
FINa B
- A entra en
FIN_WAIT_1estado
- B recibe
FIN
- B envía
ACKa A
- B entra en
CLOSE_WAITestado
- A recibe
ACK
- A entra en
FIN_WAIT_2estado
- B llama
close()
- B envía
FINa A
- B entra en
LAST_ACKestado
- A recibe
FIN
- A envía
ACKa B
- A entra en
TIME_WAITestado
- B recibe
ACK
- B pasa al
CLOSEDestado, es decir, se elimina de las tablas de conectores
TIEMPO DE ESPERA
Por lo tanto, el par que inicia la terminación, es decir, llama close()primero, terminará en el TIME_WAITestado.
Para comprender por qué el TIME_WAITestado es nuestro amigo, lea la sección 2.7 de la tercera edición de "Programación de redes UNIX" de Stevens et al (página 43).
Sin embargo, puede ser un problema con muchos enchufes en TIME_WAIT estado en un servidor ya que eventualmente podría evitar que se acepten nuevas conexiones.
Para solucionar este problema, he visto muchas sugerencias para configurar la opción de socket SO_LINGER con el tiempo de espera 0 antes de llamar close(). Sin embargo, esta es una mala solución ya que hace que la conexión TCP finalice con un error.
En su lugar, diseñe su protocolo de aplicación para que la terminación de la conexión siempre se inicie desde el lado del cliente. Si el cliente siempre sabe cuándo ha leído todos los datos restantes, puede iniciar la secuencia de terminación. Por ejemplo, un navegador sabe por el Content-Lengthencabezado HTTP cuándo ha leído todos los datos y puede iniciar el cierre. (Sé que en HTTP 1.1 lo mantendrá abierto durante un tiempo para una posible reutilización y luego lo cerrará).
Si el servidor necesita cerrar la conexión, diseñe el protocolo de aplicación para que el servidor le pida al cliente que llame close().
Cuándo usar SO_LINGER con tiempo de espera 0
Una vez más, de acuerdo con la tercera edición de "Programación de red UNIX", página 202-203, la configuración SO_LINGERcon tiempo de espera 0 antes de la llamada close()hará que no se inicie la secuencia de terminación normal .
En cambio, el par que configura esta opción y llama close()enviará un RST(restablecimiento de conexión) que indica una condición de error y así es como se percibirá en el otro extremo. Por lo general, verá errores como "Conexión restablecida por par".
Por lo tanto, en la situación normal, es una muy mala idea establecer SO_LINGERcon el tiempo de espera 0 antes de llamar close(); de ahora en adelante, se llama cierre abortivo. , en una aplicación de servidor.
Sin embargo, cierta situación justifica hacerlo de todos modos:
- Si el cliente de su aplicación de servidor se comporta mal (se agota el tiempo de espera, devuelve datos no válidos, etc.), un cierre abortivo tiene sentido para evitar quedarse atascado
CLOSE_WAITo terminar en el TIME_WAITestado.
- Si debe reiniciar la aplicación de su servidor, que actualmente tiene miles de conexiones de cliente, puede considerar configurar esta opción de socket para evitar miles de sockets de servidor
TIME_WAIT(al llamar close()desde el extremo del servidor), ya que esto podría evitar que el servidor obtenga puertos disponibles para nuevas conexiones de cliente. después de reiniciarse.
- En la página 202 del libro antes mencionado, dice específicamente: "Hay ciertas circunstancias que justifican el uso de esta función para enviar un cierre abortivo. Un ejemplo es un servidor de terminal RS-232, que puede bloquearse para siempre al
CLOSE_WAITintentar entregar datos a un terminal atascado puerto, pero restablecería correctamente el puerto atascado si tuviera RSTque descartar los datos pendientes ".
Recomendaría este extenso artículo que creo que da una muy buena respuesta a tu pregunta.