Une connexion de socket TCP a-t-elle un «keep alive»?

J’ai entendu parler de HTTP keep-alive mais pour le moment je veux ouvrir une connexion socket avec un serveur distant.
Maintenant, cette connexion socket restra-t-elle ouverte pour toujours ou y a-t-il une limite de temporisation associée à HTTP keep-alive?

Les sockets TCP restnt ouverts jusqu’à leur fermeture.

Cela dit, il est très difficile de détecter une connexion brisée (cassée, comme dans un routeur mort, etc., par opposition à fermée) sans envoyer de données, donc la plupart des applications font une sorte de réaction ping / pong la connexion est toujours réelle.

Maintenant, cette connexion socket restra-t-elle ouverte pour toujours ou y a-t-il une limite de temporisation associée à HTTP keep-alive?

La réponse courte est oui , il y a un délai d’attente et il est appliqué via TCP Keep-Alive.

Si vous souhaitez configurer le délai d’expiration, consultez la section “Modification des délais TCP” ci-dessous.

introduction

Les connexions TCP se composent de deux sockets, une à chaque extrémité de la connexion. Lorsqu’un côté veut mettre fin à la connexion, il envoie un paquet RST que l’autre partie reconnaît et ferme tous les deux ses sockets.

Jusqu’à ce que cela se produise, cependant, les deux parties garderont leur socket ouvert indéfiniment. Cela laisse ouverte la possibilité qu’un côté ferme son socket, intentionnellement ou à cause d’une erreur, sans informer l’autre extrémité via RST . Pour détecter ce scénario et fermer les connexions obsolètes, le processus TCP Keep Alive est utilisé.

Processus de maintien en vie

Il existe trois propriétés configurables qui déterminent le fonctionnement de Keep-Alives. Sous Linux, ils sont 1 :

  • tcp_keepalive_time
    • 7200 secondes par défaut
  • tcp_keepalive_probes
    • par défaut 9
  • tcp_keepalive_intvl
    • 75 secondes par défaut

Le processus fonctionne comme ceci:

  1. Le client ouvre la connexion TCP
  2. Si la connexion est silencieuse pour les secondes tcp_keepalive_time , envoyez un seul paquet ACK vide. 1
  3. Le serveur a-t-il répondu avec un ACK correspondant?
    • Non
      1. Attendez tcp_keepalive_intvl secondes, puis envoyez un autre ACK
      2. Répétez l’opération jusqu’à ce que le nombre de sondes ACK envoyées soit égal à tcp_keepalive_probes .
      3. Si aucune réponse n’a été reçue à ce stade, envoyez un message RST et fermez la connexion.
    • Oui : retour à l’étape 2

Ce processus est activé par défaut sur la plupart des systèmes d’exploitation, et les connexions TCP mortes sont régulièrement supprimées une fois que l’autre extrémité n’a pas répondu pendant 2 heures 11 minutes (7200 secondes + 75 * 9 secondes).

Gotchas

2 heures par défaut

Comme le processus ne démarre pas avant qu’une connexion soit inactive pendant deux heures par défaut, les connexions TCP obsolètes peuvent durer très longtemps avant d’être élaguées. Cela peut être particulièrement dangereux pour les connexions coûteuses telles que les connexions à la firebase database.

Keep-Alive est facultatif

Selon la RFC 1122 4.2.3.6 , répondre et / ou relayer les paquets TCP Keep-Alive est facultatif :

Les implémenteurs PEUVENT inclure “Keep-Alives” dans leurs implémentations TCP, bien que cette pratique ne soit pas universellement acceptée. Si keep-alives sont inclus, l’application DOIT être capable de les activer ou de les désactiver pour chaque connexion TCP, et ils DOIVENT être désactivés par défaut.

Il est extrêmement important de se rappeler que les segments ACK ne contenant aucune donnée ne sont pas transmis de manière fiable par TCP.

Le raisonnement étant que les paquets Keep-Alive ne contiennent aucune donnée et ne sont pas ssortingctement nécessaires et risquent de boucher les tubes des interwebs s’ils sont surutilisés.

Dans la pratique, cependant , mon expérience a montré que cette préoccupation a diminué avec le temps, la bande passante étant devenue moins chère; et donc les paquets Keep-Alive ne sont généralement pas supprimés. La documentation Amazon EC2, par exemple, donne une approbation indirecte à Keep-Alive. Par conséquent, si vous hébergez avec AWS, vous pouvez vous fier à Keep-Alive, mais votre kilométrage peut varier.

Modification des délais d’attente TCP

Par socket

Malheureusement, étant donné que les connexions TCP sont gérées au niveau du système d’exploitation, Java ne prend pas en charge la configuration des délais d’attente au niveau de chaque socket, par exemple dans java.net.Socket . J’ai trouvé des tentatives 3 pour utiliser Java Native Interface (JNI) pour créer des sockets Java qui appellent du code natif pour configurer ces options, mais aucune ne semble avoir une adoption ou une prise en charge communautaire étendue.

Au lieu de cela, vous devrez peut-être appliquer votre configuration au système d’exploitation dans son ensemble. Sachez que cette configuration affectera toutes les connexions TCP exécutées sur l’ensemble du système.

Linux

Les parameters TCP Keep-Alive actuellement configurés se trouvent dans

  • /proc/sys/net/ipv4/tcp_keepalive_time
  • /proc/sys/net/ipv4/tcp_keepalive_probes
  • /proc/sys/net/ipv4/tcp_keepalive_intvl

Vous pouvez mettre à jour l’un de ces éléments comme suit:

 # 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 

Ces modifications ne persisteront pas lors d’un redémarrage. Pour apporter des modifications persistantes, utilisez sysctl :

 sysctl -w net.ipv4.tcp_keepalive_time=180 net.ipv4.tcp_keepalive_probes=3 net.ipv4.tcp_keepalive_intvl=10 

Mac OS X

Les parameters actuellement configurés peuvent être visualisés avec 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 

À noter que Mac OS X définit keepidle et keepintvl en unités de millisecondes, contrairement à Linux qui utilise les secondes.

Les propriétés peuvent être définies avec sysctl qui persistera lors des redémarrages:

 sysctl -w net.inet.tcp.keepidle=180000 net.inet.tcp.keepcnt=3 net.inet.tcp.keepintvl=10000 

Alternativement, vous pouvez les append à /etc/sysctl.conf (en créant le fichier s’il n’existe pas).

 $ cat /etc/sysctl.conf net.inet.tcp.keepidle=180000 net.inet.tcp.keepintvl=10000 net.inet.tcp.keepcnt=3 

les fenêtres

Je n’ai pas de machine Windows pour confirmer, mais vous devriez trouver les parameters respectifs de TCP Keep-Alive dans le registre à

\HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\TCPIP\Parameters

Notes de bas de page

1. Voir man tcp pour plus d’informations.

2. Ce paquet est souvent appelé paquet “Keep-Alive”, mais dans la spécification TCP, il ne s’agit que d’un paquet ACK standard. Les applications telles que Wireshark peuvent le nommer comme un paquet “Keep-Alive” par méta-parsing de la séquence et des numéros d’accusé de réception qu’il contient en référence aux communications précédentes sur le socket.

3. Voici quelques exemples de recherches Google: lucwilliams / JavaLinuxNet et flonatel / libdontdie .

Vous recherchez l’option de socket SO_KEEPALIVE.

L’ API Java Socket expose “keep-alive” aux applications via les méthodes setKeepAlive et getKeepAlive .

EDIT: SO_KEEPALIVE est implémenté dans les stacks de protocole réseau du système d’exploitation sans envoyer de “vraies” données. L’intervalle persistant dépend du système d’exploitation et peut être ajusté via un paramètre du kernel.

Comme aucune donnée n’est envoyée, SO_KEEPALIVE peut uniquement tester la qualité de vie de la connexion réseau, et non la vivacité du service auquel la socket est connectée. Pour tester ce dernier, vous devez implémenter quelque chose qui implique l’envoi de messages au serveur et l’obtention d’une réponse.

TCP keepalive et HTTP keepalive sont des concepts très différents. Dans TCP, le keepalive est le paquet administratif envoyé pour détecter les connexions obsolètes. Dans HTTP, keepalive signifie l’état de connexion persistant.

Ceci est de la spécification TCP,

Les paquets Keep-Alive DOIVENT être envoyés uniquement lorsqu’aucun paquet de données ou d’accusé de réception n’a été reçu pour la connexion dans un intervalle. Cet intervalle DOIT être configurable et DOIT être par défaut d’au moins deux heures.

Comme vous pouvez le constater, l’intervalle TCP keepalive par défaut est trop long pour la plupart des applications. Vous devrez peut-être append keepalive dans votre protocole d’application.

Si vous êtes derrière un NAT masquant (comme la plupart des utilisateurs domestiques le sont actuellement), il existe un pool limité de ports externes, qui doivent être partagés entre les connexions TCP. Par conséquent, le masquage de NAT suppose qu’une connexion a été interrompue si aucune donnée n’a été envoyée pendant une certaine période.

Cela et d’autres problèmes similaires (n’importe où entre les deux points d’extrémité) peuvent signifier que la connexion ne fonctionnera plus si vous essayez d’envoyer des données après une période d’inactivité raisonnable. Cependant, vous ne pouvez pas découvrir cela jusqu’à ce que vous essayez d’envoyer des données.

Utiliser keepalives réduit à la fois les risques d’interruption de la connexion quelque part et vous permet également de découvrir une connexion brisée plus tôt.

Voici quelques ouvrages supplémentaires sur keepalive qui l’expliquent de manière beaucoup plus détaillée.

http://www.tldp.org/HOWTO/html_single/TCP-Keepalive-HOWTO

Comme Java ne vous permet pas de contrôler les temps de maintien réels, vous pouvez utiliser les exemples pour les modifier si vous utilisez un kernel Linux (ou un système d’exploitation basé sur proc).