Contrôle de l'Application de retransmission TCP sur Linux
Pour les impatients:
Comment modifier la valeur de /proc/sys/net/ipv4/tcp_retries2
pour une seule connexion sous Linux, à l'aide de setsockopt()
, ioctl()
ou tel, ou est-il possible?
Plus description:
Je suis de développer une application qui utilise le temps d'interrogation des requêtes HTTP. Sur le côté serveur, elle doit être connue lorsque le client a fermé la connexion. La précision n'est pas critique, mais il ne peut certainement pas être de 15 minutes. Plus proche d'une minute, ferait l'affaire.
Pour ceux qui ne connaissent pas le concept, un temps d'interrogation de la requête HTTP fonctionne comme ceci:
- Le client envoie une requête
- Le serveur répond avec des en-têtes HTTP, mais laisse la réponse de l'ouvrir. Encodage de transfert en bloc est utilisé, ce qui permet au serveur d'envoie des bits de données à mesure qu'ils deviennent disponibles.
- Lorsque toutes les données sont envoyées, le serveur envoie un "morceau de clôture" pour signaler que la réponse est complète.
Dans mon application, le serveur envoie des "battements de coeur" pour le client, chaque maintenant puis (30 secondes par défaut). Un battement de coeur est juste un caractère de saut de ligne qui est envoyé en réponse morceau. Ceci est fait afin de garder la ligne est occupée, de sorte que nous notifier la perte de connexion.
Il n'y a pas de problème lorsque le client s'arrête correctement. Mais quand il est arrêté par la force (la machine du client perd de l'énergie, par exemple), une réinitialisation TCP n'est pas envoyé. Dans ce cas, le serveur envoie un battement de cœur, et que le client n'a pas d'accusé de réception. Après cela, le serveur continue à retransmettre le paquet pour environ 15 minutes après avoir mis en place de reporting et de l'échec à l'application de la couche de (notre serveur HTTP). Et 15 minutes est trop long d'attendre dans mon cas.
Je peux contrôler le temps de retransmission par écrit les fichiers suivants dans /proc/sys/net/ipv4/
:
tcp_retries1 - INTEGER
This value influences the time, after which TCP decides, that
something is wrong due to unacknowledged RTO retransmissions,
and reports this suspicion to the network layer.
See tcp_retries2 for more details.
RFC 1122 recommends at least 3 retransmissions, which is the
default.
tcp_retries2 - INTEGER
This value influences the timeout of an alive TCP connection,
when RTO retransmissions remain unacknowledged.
Given a value of N, a hypothetical TCP connection following
exponential backoff with an initial RTO of TCP_RTO_MIN would
retransmit N times before killing the connection at the (N+1)th RTO.
The default value of 15 yields a hypothetical timeout of 924.6
seconds and is a lower bound for the effective timeout.
TCP will effectively time out at the first RTO which exceeds the
hypothetical timeout.
RFC 1122 recommends at least 100 seconds for the timeout,
which corresponds to a value of at least 8.
La valeur par défaut de tcp_retries2
est en effet de 8, et de mon expérience de 15 minutes (900 secondes) de la retransmission est en ligne avec la documentation du noyau cité ci-dessus.
Si je change la valeur de tcp_retries2
à 5 par exemple, la connexion meurt beaucoup plus rapide. Mais le définissant comme cela affecte toutes les connexions dans le système, et je tiens vraiment à le définir pour cela une longue interrogation connexion uniquement.
Une citation de la RFC 1122:
4.2.3.5 TCP Connection Failures
Excessive retransmission of the same segment by TCP
indicates some failure of the remote host or the Internet
path. This failure may be of short or long duration. The
following procedure MUST be used to handle excessive
retransmissions of data segments [IP:11]:
(a) There are two thresholds R1 and R2 measuring the amount
of retransmission that has occurred for the same
segment. R1 and R2 might be measured in time units or
as a count of retransmissions.
(b) When the number of transmissions of the same segment
reaches or exceeds threshold R1, pass negative advice
(see Section 3.3.1.4) to the IP layer, to trigger
dead-gateway diagnosis.
(c) When the number of transmissions of the same segment
reaches a threshold R2 greater than R1, close the
connection.
(d) An application MUST be able to set the value for R2 for
a particular connection. For example, an interactive
application might set R2 to "infinity," giving the user
control over when to disconnect.
(e) TCP SHOULD inform the application of the delivery
problem (unless such information has been disabled by
the application; see Section 4.2.4.1), when R1 is
reached and before R2. This will allow a remote login
(User Telnet) application program to inform the user,
for example.
Il me semble que tcp_retries1
et tcp_retries2
dans Linux correspondent à R1
et R2
dans la RFC. Le RFC énonce clairement (au point d) que de la conformation de la mise en œuvre DOIT permettre de définir la valeur de R2
, mais je n'ai trouvé aucun moyen de le faire à l'aide de setsockopt()
, ioctl()
ou telle.
Une autre option serait d'obtenir une notification lorsque R1
est dépassée (point e). Ce n'est pas aussi bon que le réglage de R2
, même si, comme je pense que R1
est frappé assez rapidement (en quelques secondes), et la valeur de R1
ne peut pas être défini par connexion, ou au moins le RFC ne l'exige pas.
- linux 4.9 tcp_retries2 = 15. par défaut (par docs), pas défini dans /etc/sysctl.conf
Vous devez vous connecter pour publier un commentaire.
Ressemble à ce qui a été ajouté dans le Noyau 2.6.37.
S'engager diff de noyau Git et Extrait de journal des modifications ci-dessous;
Je suggère que si le
TCP_USER_TIMEOUT
option de socket décrit par Kimvais est disponible, utilisez-la. Sur les anciens noyaux où que l'option de socket n'est pas présent, vous pouvez appeler à plusieurs reprises leSIOCOUTQ
ioctl()
pour déterminer la taille de la douille de file d'attente d'envoi - si la file d'attente d'envoi n'est pas diminuer au-dessus de votre période de délai d'attente, qui indique qu'aucun des accusés de réception ont été reçues et vous pouvez fermer le socket.Après réflexion (et google), j'en suis venu à la conclusion que vous ne pouvez pas modifier
tcp_retries1
ettcp_retries2
valeur pour une seule prise, sauf si vous appliquez une sorte de patch pour le noyau. Est-ce raisonnable pour vous?Sinon, vous pouvez utiliser
TCP_KEEPALIVE
option de socket dont le but est de vérifier si une connexion est toujours active (il me semble que c'est exactement ce que vous essayez d'atteindre, de sorte qu'il a un sens). Prêter attention au fait que vous avez besoin d'ajuster ses paramètres par défaut, un peu, parce que la valeur par défaut est de déconnecter après environ 2 heures!!!C'est pour ma compréhension.
tcp_retries2 est le nombre de retransmission qui est permise par le système avant de dropant la connexion.Donc, si nous voulons changer la valeur par défaut de tcp_retries2 à l'aide de TCP_USER_TIMEOUT qui spécifie la quantité maximale de temps les données transmises peuvent rester sans accusé de réception, d'avoir à augmenter la valeur de TCP_USER_TIMEOUT droit?
Dans ce cas, la conction va attendre plus de temps, et ne pas retransmettre le paquet de données.
S'il vous plaît corrigez-moi, si quelque chose est faux.
Par programmation en utilisant C. Il fonctionne au moins sur Ubuntu. Mais (selon le code et les variables système) ressemble à des influences sur toutes les connexions TCP dans le système, et pas seulement une seule connexion.
tcp_retries2
pour un connexion, pas pour toutes les connexions TCP dans le système d'exploitation.