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:
- El lado del servidor
TIME_WAIT
es inofensivo - 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_WAIT
el cliente puede ser un problema: el cliente puede quedarse sin puertos disponibles, por lo que, en esencia, lo anterior recomienda trasladar la carga TIME_WAIT
al lado del cliente donde puede ser un problema, desde el lado del servidor donde no es un problema.
El lado del cliente TIME_WAIT
es, 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_LINGER
con 0 tiempo de espera, o entrometerse con tcp_tw sysctls) combata el lado del cliente TIME_WAIT
evitando 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_WAIT
es útil en absoluto. La razón TIME_WAIT
está ahí, porque evita la inyección de TCP
fragmentos obsoletos en las secuencias a las que ya no pertenecen. Para el lado del cliente, TIME_WAIT
se logra simplemente haciendo imposible crear una conexión con los mismos ip:port
pares 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_WAIT
realmente no hace nada, y simplemente se deja así porque loRFC
requiere? - ¿Es la razón por la que la recomendación es que el cliente inicie close () porque el servidor
TIME_WAIT
es inútil?
TIME_WAIT
.Respuestas:
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
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.
fuente
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.
fuente
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.
fuente
TIME_WAIT
(actualicé la pregunta con esa información). La referencia de @ Khushil no cubre losTIME_WAIT
casos del lado del servidor con suficiente detalle.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.
fuente