Итак, я провел некоторое тестирование.Исходя из моих результатов, ясно, что они зависят от базовой реализации ОС.Для справки, я проверил это на стандартном ядре Fedora: 2.6.35.10-74.fc14.x86_64
.
Суть в том, что async_resolve()
выглядит как единственный случай, когда вы можете быть в состоянии уйтибез установки deadline_timer
.Практически во всех остальных случаях это требуется для разумного поведения.
async_resolve()
Вызов async_resolve()
привел к 4 запросам с интервалом в 5 секунд.Обработчик вызывался через 20 секунд после запроса с ошибкой boost::asio::error::host_not_found
.
Мой распознаватель по умолчанию имеет тайм-аут 5 секунд с 2 попытками (resolv.h
), поэтому он, кажется, отправляет вдвое больше запросовсконфигурировано.Поведение можно изменить, установив options timeout
и options attempts
в /etc/resolv.conf
.В каждом случае число отправленных запросов было удвоено независимо от того, на что было установлено значение attempts
, а затем вызывался обработчик с ошибкой host_not_found
.
Для теста один сконфигурированный сервер имен был перенаправлен в «черную дыру».
async_connect()
При вызове async_connect()
с адресом, перенаправленным в черную дыру, обработчик вызывается с ошибкой boost::asio::error::timed_out
после ~189 секунд.
Стек отправил первоначальный SYN и 5 повторных попыток.Первая повторная попытка была отправлена через 3 секунды, причем время повторной попытки удваивалось каждый раз (3 + 6 + 12 + 24 + 48 + 96 = 189).Количество попыток может быть изменено:
% sysctl net.ipv4.tcp_syn_retries
net.ipv4.tcp_syn_retries = 5
Значение по умолчанию 5 выбрано в соответствии с RFC 1122 (4.2.3.5):
[таймеры повторной передачи] дляСегмент SYN ДОЛЖЕН быть установлен достаточно большим, чтобы обеспечить повторную передачу сегмента в течение не менее 3 минут.Конечно, приложение может закрыть соединение (т. Е. Отказаться от попытки открытия) раньше.
3 минуты = 180 секунд, хотя в RFC не указывается верхняя граница.Ничто не мешает реализации повторять попытки навсегда.
async_write()
Пока буфер отправки сокета не был заполнен, этот обработчик всегда вызывалсясразу.
Мой тест установил TCP-соединение и установил таймер для вызова async_write()
минуту спустя.В течение минуты, когда было установлено соединение, но до вызова async_write()
, я попробовал всевозможные беспорядки:
- Настройка нисходящего маршрутизатора для черной дыры последующего трафика к месту назначения.
- Очистка сеанса в нисходящем межсетевом экране, чтобы он отвечал поддельными RST из пункта назначения.
- Отключение моего Ethernet
- Работает
/etc/init.d/network stop
НетЧто бы я ни делал, следующий async_write()
немедленно вызывал бы его обработчик, чтобы сообщить об успешном выполнении.
В случае, когда брандмауэр подделывал RST, соединение было немедленно закрыто, но я не мог знать, что доЯ попытался выполнить операцию next (которая немедленно сообщит boost::asio::error::connection_reset
).В других случаях соединение будет оставаться открытым и не будет сообщать мне об ошибках до тех пор, пока не истечет время ожидания через 17-18 минут.
Наихудший случай для async_write()
- это если хост выполняет повторную передачу и буфер отправкиполный.Если буфер заполнен, async_write()
не будет вызывать его обработчик, пока не истечет время повторной передачи.Linux по умолчанию использует 15 повторных передач:
% sysctl net.ipv4.tcp_retries2
net.ipv4.tcp_retries2 = 15
Время между повторными передачами увеличивается после каждой (и основано на многих факторах, таких как предполагаемое время прохождения в оба конца конкретного соединения), но ограничено 2 минутами.Таким образом, с 15 повторными передачами по умолчанию и 2-минутным таймаутом в худшем случае верхняя граница составляет 30 минут для вызова обработчика async_write()
.При вызове error устанавливается на boost::asio::error::timed_out
.
async_read()
Это никогда не должно вызывать его обработчик, пока установлено соединениеи данные не получены.У меня не было времени проверить это.