He oído hablar de HTTP keep-alive pero por ahora quiero abrir una conexión de socket con un servidor remoto.
Ahora, ¿esta conexión de socket permanecerá abierta para siempre o hay un límite de tiempo de espera asociado similar al HTTP Keep-Alive?
He oído hablar de HTTP keep-alive pero por ahora quiero abrir una conexión de socket con un servidor remoto.
Ahora, ¿esta conexión de socket permanecerá abierta para siempre o hay un límite de tiempo de espera asociado similar al HTTP Keep-Alive?
Respuestas:
Los sockets TCP permanecen abiertos hasta que se cierran.
Dicho esto, es muy difícil detectar una conexión rota (rota, como en un enrutador muerto, etc., en lugar de estar cerrada) sin enviar datos, por lo que la mayoría de las aplicaciones hacen algún tipo de reacción de ping / pong de vez en cuando solo para asegurarse la conexión todavía está viva.
Ahora, ¿esta conexión de socket permanecerá abierta para siempre o hay un límite de tiempo de espera asociado similar al HTTP Keep-Alive?
La respuesta corta es no , no permanecerá abierto para siempre, probablemente se agotará después de unas horas. Por lo tanto , sí existe es un tiempo de espera y se hace cumplir a través de TCP Keep-Alive .
Si desea configurar el tiempo de espera de Keep-Alive en su máquina, consulte la sección "Cambiar los tiempos de espera de TCP" a continuación. De lo contrario, lea el resto de la respuesta para aprender cómo funciona TCP Keep-Alive.
Las conexiones TCP constan de dos sockets, uno en cada extremo de la conexión. Cuando un lado quiere terminar la conexión, envía un RST
paquete que el otro lado reconoce y ambos cierran sus sockets.
Sin embargo, hasta que eso suceda, ambos lados mantendrán su enchufe abierto indefinidamente. Esto deja abierta la posibilidad de que un lado cierre su enchufe, ya sea intencionalmente o por algún error, sin informar al otro extremo vía RST
. Para detectar este escenario y cerrar conexiones obsoletas, se utiliza el proceso TCP Keep Alive.
Hay tres propiedades configurables que determinan cómo funciona Keep-Alives. En Linux son 1 :
tcp_keepalive_time
tcp_keepalive_probes
tcp_keepalive_intvl
El proceso funciona así:
tcp_keepalive_time
segundos, envíe un solo ACK
paquete vacío . 1ACK
propia?
tcp_keepalive_intvl
segundos, luego envíe otroACK
ACK
sondas enviadas sea igual tcp_keepalive_probes
.RST
y finalice la conexión.Este proceso está habilitado de forma predeterminada en la mayoría de los sistemas operativos y, por lo tanto, las conexiones TCP inactivas se eliminan regularmente una vez que el otro extremo no responde durante 2 horas y 11 minutos (7200 segundos + 75 * 9 segundos).
Dado que el proceso no se inicia hasta que una conexión ha estado inactiva durante dos horas de forma predeterminada, las conexiones TCP obsoletas pueden permanecer durante mucho tiempo antes de podarse. Esto puede ser especialmente perjudicial para conexiones costosas, como conexiones de bases de datos.
De acuerdo con RFC 1122 4.2.3.6 , responder y / o retransmitir paquetes TCP Keep-Alive es opcional :
Los implementadores PUEDEN incluir "keep-alives" en sus implementaciones de TCP, aunque esta práctica no es universalmente aceptada. Si se incluyen los Keep-Alives, la aplicación DEBE poder activarlos o desactivarlos para cada conexión TCP, y DEBEN estar desactivados de forma predeterminada.
...
Es extremadamente importante recordar que los segmentos ACK que no contienen datos no son transmitidos de manera confiable por TCP.
El razonamiento es que los paquetes Keep-Alive no contienen datos y no son estrictamente necesarios y corren el riesgo de obstruir los tubos de las redes si se usan en exceso.
Sin embargo , en la práctica , mi experiencia ha sido que esta preocupación ha disminuido con el tiempo a medida que el ancho de banda se ha vuelto más barato; y por lo tanto, los paquetes Keep-Alive no suelen descartarse. La documentación de Amazon EC2, por ejemplo, brinda un respaldo indirecto de Keep-Alive, por lo que si está hospedando con AWS, es probable que esté seguro confiando en Keep-Alive, pero su millaje puede variar.
Desafortunadamente, dado que las conexiones TCP se administran en el nivel del sistema operativo, Java no admite la configuración de tiempos de espera en un nivel por socket como en java.net.Socket
. Encontré algunos intentos 3 de usar la Interfaz nativa de Java (JNI) para crear sockets de Java que llaman al código nativo para configurar estas opciones, pero ninguno parece tener una adopción o soporte de la comunidad generalizada.
En su lugar, es posible que se vea obligado a aplicar su configuración al sistema operativo en su conjunto. Tenga en cuenta que esta configuración afectará a todas las conexiones TCP que se ejecutan en todo el sistema.
Los ajustes TCP Keep-Alive configurados actualmente se pueden encontrar en
/proc/sys/net/ipv4/tcp_keepalive_time
/proc/sys/net/ipv4/tcp_keepalive_probes
/proc/sys/net/ipv4/tcp_keepalive_intvl
Puede actualizar cualquiera de estos así:
# Send first Keep-Alive packet when a TCP socket has been idle for 3 minutes
$ echo 180 > /proc/sys/net/ipv4/tcp_keepalive_time
# Send three Keep-Alive probes...
$ echo 3 > /proc/sys/net/ipv4/tcp_keepalive_probes
# ... spaced 10 seconds apart.
$ echo 10 > /proc/sys/net/ipv4/tcp_keepalive_intvl
Estos cambios no se mantendrán hasta que se reinicie. Para realizar cambios persistentes, use sysctl
:
sysctl -w net.ipv4.tcp_keepalive_time=180 net.ipv4.tcp_keepalive_probes=3 net.ipv4.tcp_keepalive_intvl=10
Los ajustes configurados actualmente se pueden ver con sysctl
:
$ sysctl net.inet.tcp | grep -E "keepidle|keepintvl|keepcnt"
net.inet.tcp.keepidle: 7200000
net.inet.tcp.keepintvl: 75000
net.inet.tcp.keepcnt: 8
Es de destacar que Mac OS X define keepidle
y keepintvl
en unidades de milisegundos a diferencia de Linux que usa segundos.
Se pueden configurar las propiedades con las sysctl
que se mantendrán estas configuraciones durante los reinicios:
sysctl -w net.inet.tcp.keepidle=180000 net.inet.tcp.keepcnt=3 net.inet.tcp.keepintvl=10000
Alternativamente, puede agregarlos a /etc/sysctl.conf
(creando el archivo si no existe).
$ cat /etc/sysctl.conf
net.inet.tcp.keepidle=180000
net.inet.tcp.keepintvl=10000
net.inet.tcp.keepcnt=3
No tengo una máquina con Windows para confirmar, pero debería encontrar la configuración de TCP Keep-Alive respectiva en el registro en
\HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\TCPIP\Parameters
Notas al pie
1. Consulte man tcp
para obtener más información.
2. Este paquete a menudo se denomina paquete "Keep-Alive", pero dentro de la especificación TCP es simplemente un ACK
paquete normal . Aplicaciones como Wireshark pueden etiquetarlo como un paquete "Keep-Alive" mediante el metanálisis de la secuencia y los números de reconocimiento que contiene en referencia a las comunicaciones anteriores en el socket.
3. Algunos ejemplos que encontré en una búsqueda básica en Google son lucwilliams / JavaLinuxNet y flonatel / libdontdie .
$ no -a | grep tcp_keep
comando.
Está buscando la opción de socket SO_KEEPALIVE.
La API de Java Socket expone "mantener vivo" a las aplicaciones a través de los métodos setKeepAlive
y getKeepAlive
.
EDITAR: SO_KEEPALIVE se implementa en las pilas de protocolos de red del SO sin enviar ningún dato "real". El intervalo de mantenimiento depende del sistema operativo y se puede ajustar mediante un parámetro del kernel.
Dado que no se envían datos, SO_KEEPALIVE solo puede probar la vida útil de la conexión de red, no la vida útil del servicio al que está conectado el enchufe. Para probar este último, debe implementar algo que implique enviar mensajes al servidor y obtener una respuesta.
El keepalive de TCP y el keepalive de HTTP son conceptos muy diferentes. En TCP, keepalive es el paquete administrativo enviado para detectar una conexión obsoleta. En HTTP, keepalive significa el estado de conexión persistente.
Esto es de la especificación TCP,
Los paquetes Keep-Alive solo DEBEN enviarse cuando no se hayan recibido datos o paquetes de reconocimiento para la conexión dentro de un intervalo. Este intervalo DEBE ser configurable y DEBE ser predeterminado en no menos de dos horas.
Como puede ver, el intervalo de mantenimiento de TCP predeterminado es demasiado largo para la mayoría de las aplicaciones. Es posible que deba agregar keepalive en su protocolo de aplicación.
HTTP/1.0
cada solicitud / respuesta es necesario volver a conectarse al servidor. Porque HTTP/1.1
introdujeron un Keep-Alive
encabezado que podría usarse para hacer que el servidor no cancele la conexión después de que haya terminado de procesar la respuesta para facilitar la solicitud de más archivos y permitir la 'canalización'; enviar múltiples solicitudes y luego esperar a que todos los datos regresen.
Si está detrás de un NAT enmascarado (como la mayoría de los usuarios domésticos en estos días), hay un grupo limitado de puertos externos, y estos deben compartirse entre las conexiones TCP. Por lo tanto, los NAT enmascarados tienden a asumir que una conexión se ha terminado si no se han enviado datos durante un cierto período de tiempo.
Este y otros problemas similares (en cualquier lugar entre los dos puntos finales) pueden significar que la conexión ya no "funcionará" si intenta enviar datos después de un período inactivo razonable. Sin embargo, es posible que no descubra esto hasta que intente enviar datos.
El uso de keepalives reduce la posibilidad de que la conexión se interrumpa en algún punto de la línea y también le permite descubrir una conexión rota antes.
Aquí hay algo de literatura complementaria sobre keepalive que lo explica con mucho más detalle.
http://www.tldp.org/HOWTO/html_single/TCP-Keepalive-HOWTO
Dado que Java no le permite controlar los tiempos reales de mantenimiento, puede usar los ejemplos para cambiarlos si está usando un kernel de Linux (o un sistema operativo basado en proc).
En JAVA Socket: las conexiones TCP se administran en el nivel del sistema operativo, java.net.Socket no proporciona ninguna función incorporada para establecer tiempos de espera para el paquete keepalive en un nivel por socket. Pero podemos habilitar la opción keepalive para el socket de Java, pero de forma predeterminada, el proceso toma 2 horas 11 minutos (7200 segundos) después de una conexión tcp obsoleta. Esta conexión de causa estará disponible durante mucho tiempo antes de la purga. Así que encontramos alguna solución para usar la Interfaz nativa de Java (JNI) que llama al código nativo (c ++) para configurar estas opciones.
**** Sistema operativo Windows ****
En el sistema operativo Windows, keepalive_time y keepalive_intvl se pueden configurar, pero tcp_keepalive_probes no se puede cambiar. De forma predeterminada, cuando se inicializa un socket TCP, se establece el tiempo de espera de mantenimiento en 2 horas y el intervalo de mantenimiento en 1 segundo. El valor predeterminado de todo el sistema del tiempo de espera para mantener vivo se puede controlar mediante la configuración del registro KeepAliveTime, que toma un valor en milisegundos.
En Windows Vista y versiones posteriores, el número de sondeos de mantenimiento (retransmisiones de datos) se establece en 10 y no se puede cambiar.
En Windows Server 2003, Windows XP y Windows 2000, la configuración predeterminada para el número de sondeos de mantenimiento es 5. El número de sondeos de mantenimiento es controlable. Para Windows Winsock, la biblioteca IOCTL se utiliza para configurar los parámetros tcp-keepalive.
int WSAIoctl (SocketFD, // descriptor que identifica un socket SIO_KEEPALIVE_VALS, // dwIoControlCode (LPVOID) lpvInBuffer, // puntero a tcp_keepalive struct (DWORD) cbInBuffer, // longitud del búfer de entrada NULL, // búfer de salida 0, // tamaño de búfer de salida (LPDWORD) lpcbBytesReturned, // número de bytes devueltos NULL, // estructura OVERLAPPED NULL // rutina de finalización);
SO Linux
Linux tiene soporte integrado para keepalive, que debe habilitar la red TCP / IP para poder usarlo. Los programas deben solicitar el control keepalive de sus sockets mediante la interfaz setsockopt.
int setsockopt (int socket, int level, int optname, const void * optval, socklen_t optlen)
Cada socket de cliente se creará utilizando java.net.Socket. El ID del descriptor de archivo para cada socket se recuperará usando la reflexión de Java.
Para Windows según Microsoft docs