java sockets http tcp keep-alive

java - ¿Tiene una conexión de socket TCP un "mantener vivo"?



sockets http (6)

Ahora, ¿esta conexión de socket permanecerá abierta para siempre o hay un límite de tiempo de espera asociado con ella similar al HTTP keep-alive?

La respuesta corta es, , hay un tiempo de espera y se aplica a través de TCP Keep-Alive.

Si desea configurar el tiempo de espera de Keep-Alive, consulte la sección "Cambio del tiempo de espera TCP" a continuación.

Introducción

Las conexiones TCP constan de dos enchufes, uno en cada extremo de la conexión. Cuando un lado quiere terminar la conexión, envía un paquete RST que el otro lado reconoce y ambos cierran sus enchufes.

Hasta que eso suceda, sin embargo, ambos lados mantendrán su socket abierto indefinidamente. Esto deja abierta la posibilidad de que un lado pueda cerrar su zócalo, ya sea intencionalmente o debido a algún error, sin informar al otro extremo a través de RST . Para detectar este escenario y cerrar conexiones obsoletas, se utiliza el proceso TCP Keep Alive.

Proceso Keep-Alive

Hay tres propiedades configurables que determinan cómo funciona Keep-Alives. En Linux son 1 :

  • tcp_keepalive_time
    • predeterminado 7200 segundos
  • tcp_keepalive_probes
    • predeterminado 9
  • tcp_keepalive_intvl
    • predeterminado 75 segundos

El proceso funciona así:

  1. El cliente abre la conexión TCP
  2. Si la conexión es silenciosa durante tcp_keepalive_time segundos, envíe un único paquete de ACK vacío. 1
  3. ¿Respondió el servidor con un ACK correspondiente propio?
    • No
      1. Espere tcp_keepalive_intvl segundos, luego envíe otro ACK
      2. Repita hasta que la cantidad de sondas ACK que se han enviado sea igual a tcp_keepalive_probes .
      3. Si no se ha recibido respuesta en este punto, envíe un RST y finalice la conexión.
    • : regrese al paso 2

Este proceso está habilitado por defecto en la mayoría de los sistemas operativos y, por lo tanto, las conexiones TCP muertas se eliminan periódicamente una vez que el otro extremo ha dejado de responder durante 2 horas y 11 minutos (7200 segundos + 75 * 9 segundos).

Gotchas

2 horas predeterminadas

Dado que el proceso no comienza hasta que una conexión ha estado inactiva durante dos horas por defecto, las conexiones TCP obsoletas pueden prolongarse mucho tiempo antes de ser eliminadas. Esto puede ser especialmente dañino para conexiones caras como conexiones a bases de datos.

Keep-Alive es opcional

De acuerdo con RFC 1122 4.2.3.6 , responder y / o transmitir paquetes TCP Keep-Alive es opcional :

Los implementadores PUEDEN incluir "keep-alives" en sus implementaciones TCP, aunque esta práctica no es universalmente aceptada. Si se incluyen keep-alives, la aplicación DEBE poder activarlos o desactivarlos para cada conexión TCP, y DEBEN desactivarse de forma predeterminada.

...

Es extremadamente importante recordar que los segmentos de 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 interwebs si se usan en exceso.

En la práctica , sin embargo , 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 generalmente no se descartan. La documentación de Amazon EC2, por ejemplo, ofrece una aprobación indirecta de Keep-Alive, por lo que si está alojando con AWS, es probable que confíe en Keep-Alive, pero su millaje puede variar.

Cambiar los tiempos de espera de TCP

Por zócalo

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 . He encontrado algunos intentos 3 de utilizar Java Native Interface (JNI) para crear sockets de Java que llaman al código nativo para configurar estas opciones, pero ninguno parece tener una amplia adopción o soporte de la comunidad.

En cambio, puede verse obligado a aplicar su configuración al sistema operativo como un todo. Tenga en cuenta que esta configuración afectará todas las conexiones TCP que se ejecutan en todo el sistema.

Linux

La configuración TCP Keep-Alive actualmente configurada se puede 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 como sigue:

# 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

Tales cambios no persistirán durante un reinicio. 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

Mac OS X

La configuración actualmente configurada se puede 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

Cabe destacar que Mac OS X define keepidle y keepintvl en unidades de milisegundos en lugar de Linux, que usa segundos.

Las propiedades se pueden establecer con sysctl que persistirá en 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

Windows

No tengo una máquina con Windows para confirmar, pero debe encontrar las configuraciones TCP Keep-Alive respectivas en el registro en

/HKEY_LOCAL_MACHINE/System/CurrentControlSet/Services/TCPIP/Parameters

Consulte here para obtener más información sobre los tiempos de espera de Windows y TCP.

Notas a pie de página

1. Ver man tcp para más información.

2. Este paquete a menudo se denomina paquete "Keep-Alive", pero dentro de la especificación TCP es solo un paquete ACK regular. Aplicaciones como Wireshark pueden etiquetarlo como un paquete "Keep-Alive" mediante el metanálisis de la secuencia y los números de acuse de recibo que contiene en referencia a las comunicaciones anteriores en el socket.

3. Algunos ejemplos que encontré en una búsqueda básica de Google son lucwilliams/JavaLinuxNet y flonatel/libdontdie .

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 con ella similar al HTTP keep-alive?


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

Debido a 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).


Está buscando la opción de socket SO_KEEPALIVE.

La API Java Socket expone "keep-alive" 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 sistema operativo sin enviar ningún dato "real". El intervalo keep-alive depende del sistema operativo y puede sintonizarse mediante un parámetro kernel.

Como no se envían datos, SO_KEEPALIVE solo puede probar la vitalidad de la conexión de red, no la vitalidad del servicio al que está conectado el socket. Para probar esto último, debe implementar algo que implique el envío de mensajes al servidor y obtener una respuesta.


Los sockets TCP permanecen abiertos hasta que se cierran.

Dicho esto, es muy difícil detectar una conexión interrumpida (rota, como en un enrutador muerto, etc., en lugar de cerrada) sin enviar datos, por lo que la mayoría de las aplicaciones hacen alguna especie de reacción ping / pong cada tanto para asegurarse la conexión todavía está viva.


Si está detrás de un NAT enmascarado (como la mayoría de los usuarios domésticos lo son en la actualidad), existe un grupo limitado de puertos externos, que deben compartirse entre las conexiones TCP. Por lo tanto, los NAT enmascarados tienden a suponer que se ha terminado una conexión si no se han enviado datos durante un cierto período de tiempo.

Este y otros problemas similares (en cualquier punto 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 momento, y también le permite saber antes sobre una conexión interrumpida.


TCP keepalive y HTTP keepalive son conceptos muy diferentes. En TCP, el keepalive es el paquete administrativo enviado para detectar conexión obsoleta. En HTTP, keepalive significa el estado de conexión persistente.

Esto es de la especificación TCP,

Los paquetes Keep-alive DEBEN enviarse solo cuando no se hayan recibido datos o paquetes de acuse de recibo para la conexión dentro de un intervalo. Este intervalo DEBE ser configurable y DEBE predeterminado a no menos de dos horas.

Como puede ver, el intervalo TCP keepalive predeterminado es demasiado largo para la mayoría de las aplicaciones. Puede que tenga que agregar keepalive en su protocolo de aplicación.