¿Cómo funciona realmente el servidor `TIME_WAIT`?

11

Sé que hay bastantes preguntas SE sobre esto, y creo que leí tantas como importa antes de llegar a este punto.

Por "lado del servidor TIME_WAIT" me refiero al estado de un par de sockets del lado del servidor que tuvo su cierre () iniciado en el lado del servidor.

A menudo veo estas declaraciones que me parecen contradictorias:

  1. El lado del servidor TIME_WAITes inofensivo
  2. Debe diseñar sus aplicaciones de red para que los clientes inicien close (), por lo tanto, que el cliente lleve TIME_WAIT

La razón por la que encuentro esto contradictorio es porque TIME_WAITel cliente puede ser un problema: el cliente puede quedarse sin puertos disponibles, por lo que, en esencia, lo anterior recomienda trasladar la carga TIME_WAITal lado del cliente donde puede ser un problema, desde el lado del servidor donde no es un problema.

El lado del cliente TIME_WAITes, por supuesto, solo un problema para un número limitado de casos de uso. La mayoría de las soluciones cliente-servidor involucrarían un servidor y muchos clientes, los clientes generalmente no manejan un volumen de conexiones lo suficientemente alto como para que sea un problema, e incluso si lo hacen, hay una serie de recomendaciones para "cuerdo" ( a diferencia de SO_LINGERcon 0 tiempo de espera, o entrometerse con tcp_tw sysctls) combata el lado del cliente TIME_WAITevitando crear demasiadas conexiones demasiado rápido. Pero eso no siempre es factible, por ejemplo, para clases de aplicaciones como:

  • sistemas de monitoreo
  • generadores de carga
  • proxies

Por otro lado, ni siquiera entiendo cómo el lado del servidor TIME_WAITes útil en absoluto. La razón TIME_WAITestá ahí, porque evita la inyección de TCPfragmentos obsoletos en las secuencias a las que ya no pertenecen. Para el lado del cliente, TIME_WAITse logra simplemente haciendo imposible crear una conexión con los mismos ip:portpares que podría haber tenido esta conexión obsoleta (los pares usados ​​están bloqueados TIME_WAIT). Pero para el lado del servidor, esto no se puede evitar, ya que la dirección local tendrá el puerto de aceptación, y siempre será la misma, y ​​el servidor no puede (AFAIK, solo tengo la prueba empírica) negar la conexión simplemente porque un par entrante crearía el mismo par de direcciones que ya existe en la tabla de socket.

Escribí un programa que muestra que TIME-WAIT del lado del servidor se ignora. Además, debido a que la prueba se realizó en 127.0.0.1, el núcleo debe tener un bit especial que incluso le diga si es del lado del servidor o del lado del cliente (ya que de lo contrario la tupla sería la misma).

Fuente: http://pastebin.com/5PWjkjEf , probado en Fedora 22, configuración de red predeterminada.

$ gcc -o rtest rtest.c -lpthread
$ ./rtest 44400 s # will do server-side close
Will initiate server close
... iterates ~20 times successfully
^C
$ ss -a|grep 44400
tcp    TIME-WAIT  0      0            127.0.0.1:44400         127.0.0.1:44401   
$ ./rtest 44500 c # will do client-side close
Will initiate client close
... runs once and then
connecting...
connect: Cannot assign requested address

Entonces, para el lado del servidor TIME_WAIT, las conexiones en el mismo par de puertos exactos podrían restablecerse de manera inmediata y exitosa, y para el lado del cliente TIME-WAIT, en la segunda iteración connect()fallaron correctamente

Para resumir, la pregunta es doble:

  • ¿El lado del servidor TIME_WAITrealmente no hace nada, y simplemente se deja así porque lo RFCrequiere?
  • ¿Es la razón por la que la recomendación es que el cliente inicie close () porque el servidor TIME_WAITes inútil?
Pawel Veselov
fuente
No se quedará sin puertos a menos que tenga solo 1 cliente. Tiene 65535 puertos para cada combinación de IP de cliente / servidor. La conexión desde 1.2.3.4:1111 es diferente de 4.3.2.1:1111. Solo toma unos pocos bytes de memoria para cada conexión TIME_WAIT.
Marki555

Respuestas:

1

En términos de TCP , el lado del servidor aquí significa el host que tiene el socket en estado LISTEN.

RFC1122 permite que el socket en estado TIME-WAIT acepte una nueva conexión con algunas condiciones

        When a connection is closed actively, it MUST linger in
        TIME-WAIT state for a time 2xMSL (Maximum Segment Lifetime).
        However, it MAY accept a new SYN from the remote TCP to
        reopen the connection directly from TIME-WAIT state, if it:

Para obtener detalles exactos sobre las condiciones, consulte el RFC1122 . Supongo que también debe haber un ABIERTO pasivo coincidente en el zócalo (zócalo en estado ESCUCHAR).

Active OPEN (llamada de conexión del lado del cliente) no tiene esa excepción y debe dar un error cuando el socket está en TIME-WAIT, según RFC793 .

Supongo que la recomendación sobre el cliente (en términos de TCP, el host que realiza la apertura activa, es decir, la conexión) iniciada cerca es muy similar a la suya, que en el caso común extiende los sockets TIME-WAIT en más hosts donde hay abundantes recursos para los enchufes En el caso común, los clientes no envían SYN que reutilizaría los sockets TIME-WAIT en el servidor. Estoy de acuerdo en que aplicar dicha recomendación aún depende del caso de uso.

Marko Kohtala
fuente
0

Este es probablemente el ejemplo más claro de lo que hace TIME-WAIT y, lo que es más importante, por qué es importante. También explica por qué evitar algunos de los consejos 'expertos' en máquinas Linux para 'reducir' los TIEMPOS DE ESPERA.

Khushil
fuente
Todavía no explica qué sucede cuando se inicia una conexión cliente-> servidor, y un servidor tiene ese par bloqueado en un TIME_WAIT
Pawel Veselov
Consulte stackoverflow.com/questions/1490196/… : la respuesta allí es lo que está buscando.
Khushil
0

La sesión tcp se identifica mediante la tupple (sourceIP, sourcePort, destIP, destPort). Por lo tanto, TIME_WAIT funciona en todas las conexiones tcp.

Con respecto al lado de cierre, en algunos escenarios, el cierre desde el lado del cliente puede reducir los sockets TIME_WAIT en el servidor, lo que reduce ligeramente la memoria. En los casos en que se puede agotar el espacio del socket (debido al agotamiento efímero del puerto) (por ejemplo, clientes codiciosos con muchas conexiones al mismo servidor), este problema debe resolverse en cualquier lado.

basos
fuente
Por favor explique; Cuando pregunta si el TW del lado del servidor hace algo, se pregunta si la misma conexión puede reutilizarse durante el período TW. La respuesta es no porque la conexión, tal como la define la tupla, ocupa un lugar en la tabla tcp del servidor. Si el cliente intenta abrir la misma conexión pronto, recibirá un RST, negando efectivamente la conexión tcp. Por cierto, el artículo de Khushil es muy descriptivo.
basos
Lo siento mucho, su respuesta realmente responde la pregunta, la leí mal y me retracté de mi comentario. Sin embargo, también parece ser incorrecto, ya que tengo un código que parece demostrar que no hay protección del lado del servidor TIME_WAIT(actualicé la pregunta con esa información). La referencia de @ Khushil no cubre los TIME_WAITcasos del lado del servidor con suficiente detalle.
Pawel Veselov
-2

Con un protocolo poco confiable, nunca puede estar seguro de haber recibido el último mensaje de su dispositivo par, por lo tanto, es peligroso suponer que su par colgó el teléfono de manera repentina. Una de las principales desventajas del protocolo TCP es que solo unos 65000 puertos pueden abrirse simultáneamente. Pero la forma de superar esto sería pasar a una granja de servidores, que se escala mejor con la carga, que reciclando rápidamente los números de puerto. En el extremo del cliente, es muy poco probable que se quede sin puertos si se trata de una estación de trabajo básica.

jrrk
fuente
Lo siento mucho, pero esto no responde a mi pregunta.
Pawel Veselov