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

84

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?

Kevin Boyd
fuente
1
Solo para asegurarse de que "http keepalive" normalmente no está relacionado con socket keepalive, habla de la característica HTTP / 1.1 de mantener las conexiones abiertas para más solicitudes. Solo está relacionado con TCP keepalive ya que necesita detectar conexiones TCP rotas (o normalmente solo mantiene los sockets abiertos por tiempo limitado).
Eckes

Respuestas:

72

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.

Matthew Scharley
fuente
4
Es una buena idea. Usted no tiene que, pero si no lo hace, entonces no puede detectar un enlace roto hasta que alguien realmente quiere hacer algo. Lo que puede ser bueno o no (o puede importar o no), dependiendo de lo que realmente esté tratando de lograr.
Matthew Scharley
1
@Pacerier: Depende del protocolo, ya que depende totalmente del protocolo, pero para los protocolos basados ​​en texto que requieren un literal "PING" y los comandos "PONG" son bastante típicos.
Matthew Scharley
4
@MatthewScharley: Este "ping pong" ya está implementado para nosotros, en las implementaciones estándar de TCP, y se llama "keep-alive" (vea la otra respuesta popular a esta pregunta). ¿Existe alguna razón para implementarlo a nivel de la aplicación?
Tim Cooper
7
@TimCooper: Realmente no lo es. Como destaqué en los comentarios sobre otras respuestas, la implementación de TCP no es útil para la mayoría de los requisitos de nivel de aplicación . No puede enviar uno a pedido y, para la mayoría de los sistemas operativos, el tiempo de espera de mantenimiento de TCP solo se puede configurar a nivel de todo el sistema y se establece demasiado alto para que sea útil en general para las aplicaciones.
Matthew Scharley
13
@Tim El motivo de un Keep-Alive a nivel de aplicación es que el estándar TCP recomienda configurar el temporizador Keep-Alive en más de dos horas. Nunca he visto una conexión TCP sin tráfico que sobreviva esta vez. Por lo tanto, las cosas de TCP keep-alive son inútiles por defecto.
Robert
97

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.

Introducción

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 RSTpaquete 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.

Proceso Keep-Alive

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

  • tcp_keepalive_time
    • por defecto 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 permanece en silencio durante unos tcp_keepalive_timesegundos, envíe un solo ACKpaquete vacío . 1
  3. ¿El servidor respondió con una correspondencia ACKpropia?
    • No
      1. Espere unos tcp_keepalive_intvlsegundos, luego envíe otroACK
      2. Repita hasta que el número de ACKsondas enviadas sea igual tcp_keepalive_probes.
      3. Si no se ha recibido respuesta en este momento, envíe un RSTy finalice la conexión.
    • : vuelva al paso 2

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

Gotchas

2 horas por defecto

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.

Keep-Alive es opcional

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.

Cambiar los tiempos de espera de TCP

Por enchufe

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.

Linux

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

Mac OS X

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 keepidley keepintvlen unidades de milisegundos a diferencia de Linux que usa segundos.

Se pueden configurar las propiedades con las sysctlque 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

Ventanas

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 tcppara 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 ACKpaquete 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 .

Cory Klein
fuente
¡Muy útil, gracias! Una adición: para Windows es necesario reiniciar para que los nuevos valores de KeepAliveTime sean efectivos.
geld0r
En AIX, la configuración actual de TCP Keep-Alive se puede consultar mediante el $ no -a | grep tcp_keepcomando.
Jarek Przygódzki
55

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 setKeepAlivey 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.

Esteban C
fuente
4
Si soy un setKeepAlive (verdadero); ¿cuál sería el intervalo? ... también ¿Java seguirá enviando mensajes de mantenimiento de vida en el intervalo predeterminado o tendré que hacerlo programáticamente?
Kevin Boyd
3
unixguide.net/network/socketfaq/4.7.shtml Tiene una descripción de SO_KEEPALIVE. No es tanto lo que quería el OP, aunque es una opción basada en el protocolo de lo que sugerí ... sin embargo, una vez cada dos horas no servirá de mucho para las aplicaciones.
Matthew Scharley
4
@MatthewScharley Con respecto a "no debe predeterminarse a no menos de dos horas" ... significa que se permite que sea menos de dos horas, ¿verdad?
Pacerier
1
@MatthewScharley - "Tienes razón, pero eso sería específico de la implementación ..." . Un intervalo de mantenimiento que no puede ser inferior a dos horas sería tan inútil que es difícil imaginar que alguien lo implemente.
Stephen C
2
@Daniel: la alternativa (en Java) sería mantener vivo manualmente , como se mencionó anteriormente y en otras respuestas. No es bonito, pero quizás sea mejor que un cambio de la configuración predeterminada en todo el sistema operativo que podría romper los servicios del sistema u otras aplicaciones.
Stephen C
34

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.

Codificador ZZ
fuente
2
Puede modificar el intervalo de mantenimiento de TCP para adaptarlo a su aplicación. Por ejemplo, msdn.microsoft.com/en-us/library/dd877220%28VS.85%29.aspx
Dan Berindei
@ZZCoder ¿Puede explicar qué significa cuando dice "En HTTP, keepalive significa el estado de conexión persistente"?
Pacerier
1
@Pacerier: En HTTP/1.0cada solicitud / respuesta es necesario volver a conectarse al servidor. Porque HTTP/1.1introdujeron un Keep-Aliveencabezado 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.
Matthew Scharley
Básicamente significa que muchas solicitudes HTTP reutilizarán / deberían reutilizar la misma conexión TCP (estas conexiones también pueden tener actividad de mantenimiento, pero eso no se mide a HTTP, por lo que es esencialmente un concepto diferente).
Igor Čordaš
24

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.

Artelius
fuente
¡Ah! agrega un buen punto aquí, es que también debe considerar las cosas intermedias que podrían obstaculizar el funcionamiento de una conexión, como enrutadores NAT, etc.
Kevin Boyd
4
Este es un buen punto y un buen recordatorio de que hay más que tener en cuenta que solo lo que estamos implementando directamente nosotros mismos. Además, ¡¡Lemmings !!
Matthew Scharley
Tenga en cuenta que el intercambio de archivos p2p consume muchos puertos y produce muchas conexiones zombies, por lo que es más probable que NAT necesite eliminar las conexiones inactivas.
Artelius
4
No necesariamente, una conexión TCP se identifica con 4 elementos: src ip, src port, dest ip, dest port. Por lo tanto, puede reutilizar el mismo puerto externo (fuente) siempre que la ip de destino sea diferente.
Dan Berindei
1
Oh sí, tienes razón. Creo que la verdadera razón es que los NAT tienen una tabla de tamaño fijo de conexiones abiertas, debido a limitaciones de memoria y tiempo de búsqueda.
Artelius
4

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

Jeach
fuente
1

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.

Suganya Vinayakam
fuente
0

Para Windows según Microsoft docs

  • KeepAliveTime (REG_DWORD, milisegundos, por defecto no está configurado, lo que significa 7,200,000,000 = 2 horas) - análogo a tcp_keepalive_time
  • KeepAliveInterval (REG_DWORD, milisegundos, por defecto no está configurado, lo que significa 1,000 = 1 segundo) - análogo a tcp_keepalive_intvl
  • Dado que Windows Vista no existe un análogo a tcp_keepalive_probes, el valor se fija en 10 y no se puede cambiar
semen
fuente