J'ai donc fait quelques tests. Sur la base de mes résultats, il est clair qu'ils dépendent de la mise en œuvre du système d'exploitation sous-jacent. Pour référence, j'ai testé ceci avec un noyau Fedora en stock: 2.6.35.10-74.fc14.x86_64
.
L'essentiel est que async_resolve()
semble être le seul cas où vous pourriez être en mesure de sortir sans mettre un deadline_timer
. Il est pratiquement nécessaire dans tous les autres cas pour un comportement raisonnable.
async_resolve()
Un appel à async_resolve()
a donné lieu à des requêtes 4 5 secondes d'intervalle. Le gestionnaire a été appelé 20 secondes après la demande avec l'erreur boost::asio::error::host_not_found
.
Mon résolveur prend par défaut un délai de 5 secondes avec 2 tentatives (resolv.h
), il semble donc envoyer deux fois le nombre de requêtes configurées. Le comportement est modifiable en définissant options timeout
et options attempts
dans /etc/resolv.conf
. Dans tous les cas, le nombre de requêtes envoyées était double quel que soit attempts
et le gestionnaire a été appelé avec l'erreur host_not_found
par la suite.
Pour le test, le serveur de noms unique configuré était routé en noir.
async_connect()
Appel async_connect()
avec une destination noir routé trou a donné lieu dans le gestionnaire appelé à l'erreur boost::asio::error::timed_out
après 189 secondes ~.
La pile a envoyé les SYN et 5 tentatives initiaux. La première tentative a été envoyée après 3 secondes, avec le délai de nouvelle tentative doublant chaque fois (3 + 6 + 12 + 24 + 48 + 96 = 189). Le nombre de réitérations peut être modifié:
% sysctl net.ipv4.tcp_syn_retries
net.ipv4.tcp_syn_retries = 5
La valeur par défaut de 5 est choisi pour se conformer à la norme RFC 1122 (4.2.3.5):
[Les temporisateurs de retransmission] pour un segment SYN DOIT être définir assez grand pour fournir retransmission du segment pendant au moins 3 minutes. L'application peut fermer la connexion (c.-à-d., Abandonner sur la tentative ouverte) plus tôt, bien sûr.
3 minutes = 180 secondes, bien que la RFC ne semble pas spécifier de limite supérieure. Rien n'empêche une implémentation de réessayer pour toujours.
async_write()
Tant que le tampon d'envoi du socket n'a pas été complète, ce gestionnaire a toujours été appelé tout de suite.
Mon test a établi une connexion TCP et a défini un temporisateur pour appeler async_write()
une minute plus tard. Au cours de la minute où la connexion a été établie, mais avant l'appel async_write()
, j'ai essayé toutes sortes de Mayhem:
- Définition d'un routeur en aval pour le trafic ultérieur trou noir vers la destination.
- Suppression de la session dans un pare-feu en aval afin qu'elle réponde avec des RST falsifiés à partir de la destination.
- Ethernet
mon Débranchement
- Exécution
/etc/init.d/network stop
Peu importe ce que je faisais, la prochaine async_write()
serait immédiatement appeler son gestionnaire de signaler le succès.
Dans le cas où le pare-feu falsifié la TVD, la connexion a été fermée immédiatement, mais je n'avais aucun moyen de savoir que jusqu'à ce que je tentais la prochaine opération (qui immédiatement rapport boost::asio::error::connection_reset
). Dans les autres cas, la connexion resterait ouverte et ne me rapporterait pas d'erreurs jusqu'à ce qu'elle prenne fin 17-18 minutes plus tard.
Le pire des cas pour async_write()
est que l'hôte est en train de retransmettre et que le tampon d'envoi est plein.Si le tampon est plein, async_write()
n'appellera pas son gestionnaire tant que les retransmissions n'auront pas expiré. Linux par défaut à 15: retransmissions
% sysctl net.ipv4.tcp_retries2
net.ipv4.tcp_retries2 = 15
Le temps entre les retransmissions augmente après chaque (et repose sur de nombreux facteurs tels que le temps aller-retour estimé de la connexion spécifique) mais est fixée à 2 minutes. Donc, avec les 15 retransmissions par défaut et le délai le plus défavorable de 2 minutes, la limite supérieure est de 30 minutes pour que le gestionnaire async_write()
soit appelé. Lorsqu'elle est appelée, l'erreur est définie sur boost::asio::error::timed_out
.
async_read()
Cela ne devrait jamais appeler son gestionnaire tant que la connexion est établie et aucune donnée est reçue. Je n'ai pas eu le temps de le tester.
J'ai dû m'en tenir à créer moi-même 'deadline_timer', donc je serais très intéressé de voir si c'est inutile. – chrisaycock
+1 question intéressante. Je pense que la réponse dépendrait largement de la plateforme. Je suppose que vous vous souciez de Linux? –