Così ho fatto alcuni test. Sulla base dei miei risultati, è chiaro che dipendono dall'implementazione del sistema operativo sottostante. Come riferimento, ho provato questo con un kernel Fedora originale: 2.6.35.10-74.fc14.x86_64
.
La linea di fondo è che async_resolve()
sembra essere l'unico caso in cui si potrebbe essere in grado di uscire senza impostare una deadline_timer
. È praticamente richiesto in ogni altro caso per un comportamento ragionevole.
async_resolve()
Una chiamata a async_resolve()
portato in 4 interrogazioni 5 secondi di distanza. Il gestore è stato chiamato 20 secondi dopo la richiesta con l'errore boost::asio::error::host_not_found
.
Il mio resolver ha un timeout predefinito di 5 secondi con 2 tentativi (resolv.h
), quindi sembra che invii il doppio del numero di query configurate. Il comportamento è modificabile impostando options timeout
e options attempts
in /etc/resolv.conf
. In ogni caso il numero di query inviate era doppio rispetto a attempts
e il gestore veniva chiamato con l'errore host_not_found
in seguito.
Per il test, il server dei nomi configurato singolo è stato instradato in un buco nero.
async_connect()
Chiamata async_connect()
con una destinazione black-hole-instradato portato nel gestore chiamato con l'errore boost::asio::error::timed_out
dopo ~ 189 secondi.
Lo stack ha inviato i tentativi iniziali SYN e 5. Il primo tentativo è stato inviato dopo 3 secondi, con il timeout del tentativo di raddoppio ogni volta (3 + 6 + 12 + 24 + 48 + 96 = 189). Il numero di tentativi può essere modificato:
% sysctl net.ipv4.tcp_syn_retries
net.ipv4.tcp_syn_retries = 5
Il valore predefinito di 5 è scelto di osservare le RFC 1122 (4.2.3.5):
[I timer di ritrasmissione] per un segmento SYN DEVE essere impostare abbastanza grande per fornire la ritrasmissione del segmento per almeno 3 minuti. L'applicazione può chiudere la connessione (vale a dire, rinunciare al tentativo aperto) prima, naturalmente.
3 minuti = 180 secondi, sebbene l'RFC non sembri specificare un limite superiore. Non c'è nulla che impedisca a un'implementazione di riprovare per sempre.
async_write()
Finché buffer di trasmissione del socket non era pieno, questo gestore è stato sempre chiamato subito.
Il mio test ha stabilito una connessione TCP e impostato un timer per chiamare async_write()
un minuto dopo. Durante il minuto in cui è stata stabilita la connessione, ma prima della chiamata async_write()
, ho provato tutti i tipi di caos:
- Impostazione di un router a valle al buco nero traffico successivo alla destinazione.
- Cancellare la sessione in un firewall downstream in modo che risponda con gli RST falsificati dalla destinazione.
- scollega il mio Ethernet
- Esecuzione
/etc/init.d/network stop
Non importa quello che ho fatto, la prossima async_write()
sarebbe chiamare immediatamente il suo gestore di segnalare il successo.
Nel caso in cui il firewall spoofing della RST, la connessione è stata chiusa immediatamente, ma non ho avuto modo di sapere che fino a quando ho tentato il successiva operazione (che avrebbe riferire immediatamente boost::asio::error::connection_reset
). Negli altri casi, la connessione rimarrebbe aperta e non mi riporterebbe errori fino a quando non si esaurisce dopo 17-18 minuti.
Il caso peggiore per async_write()
è se l'host viene ritrasmesso e il buffer di invio è pieno.Se il buffer è pieno, async_write()
non chiamerà il gestore fino al timeout della ritrasmissione. di default di Linux a 15 ritrasmissioni:
% sysctl net.ipv4.tcp_retries2
net.ipv4.tcp_retries2 = 15
Il tempo tra le ritrasmissioni aumenta dopo ogni (e si basa su diversi fattori quali il tempo stimato di andata e ritorno del collegamento specifico), ma viene bloccato a 2 minuti. Pertanto, con le 15 ritrasmissioni predefinite e il timeout di 2 minuti nel caso peggiore, il limite superiore è di 30 minuti per il gestore async_write()
da chiamare. Quando viene chiamato, l'errore è impostato su boost::asio::error::timed_out
.
async_read()
questo non dovrebbe mai chiamare il suo gestore fino a quando la connessione è stabilita e nessun dato è ricevuto. Non ho avuto il tempo di testarlo.
Ho dovuto limitarmi a creare il mio 'deadline_timer', quindi sarei molto interessato a vedere se questo non è necessario. – chrisaycock
+1 domanda interessante. Penso che la risposta dipenda in gran parte dalla piattaforma. Suppongo che ti interessi di Linux? –