Я реализую протокол с BOOST ASIO, который повторно отправляет ответ, если он не был признан.
Я использую async_read_some()
и deadline_timer
, работающие асинхронно вместе
чтобы увидеть, получил ли я все сообщение или истекает ли таймер первым и новым
сообщение будет отправлено.
Вопрос в том, если deadline_timer
истекает первым, как мне закрыть
async_read_some()
и попробовать прочитать новое сообщение?
Или есть лучший способ реализовать протокол, который повторно отправляет сообщения?
Я не знаю, почему вы хотите прервать async_read_some
, если вы все равно хотите прочитать новое сообщение. Кажется, в протоколе, который вы реализуете, есть некоторая ошибка (или недоразумение).
Это вопрос о протоколах, а не о конкретной реализации.
Реальный вопрос: как вы синхронизируете отправку и чтение? То есть, если я отправлю сообщение узлу в вашей сети, что произойдет? Две основные идеи:
Синхронный: когда я отправляю сообщение, ожидается, что все, что я прочитаю, будет ответом на это сообщение. Другими словами, последовательность ответа на запрос выглядит следующим образом: Req1 -> Resp1 -> Req2 -> Resp2 и т. д. Вы также можете передавать запросы, т. е. Req1 -> Req2 -> Resp1 -> Resp2. Но несинхронизированные ответы не допускаются, например. это неверно: Req1 -> Req2 -> Resp2 -> Resp1. Этот синхронный подход широко используется в протоколе HTTP.
Асинхронный: с каждым сообщением я отправляю уникальный идентификатор, и все, что я читаю, также должно иметь идентификатор. Затем я сопоставляю ответ с запросом по идентификатору. При таком подходе действительно возможна следующая последовательность: Req1 -> Req2 -> Resp2 -> Resp1.
Что можно сделать при синхронном подходе по тайм-ауту? Вы все еще можете дождаться ответа, а затем отбросить его (с журналом), но это задержит каждый другой запрос из-за синхронного характера. И если партнер противен, это может привести к бесконечному ожиданию, и в конечном итоге у вас закончатся ресурсы. В качестве альтернативы вы можете просто закрыть соединение. Это безопаснее и проще, и часто это то, что выбирают разработчики.
При асинхронном подходе вы удаляете идентификатор из своей «карты обработчика идентификатора к ответу» (которую вы все равно должны поддерживать), и все. И не забудьте отбросить ответы без совпадения идентификатора (с журналом). Конечно, в конечном итоге вы также захотите закрыть неприятные связи.
Асинхронный подход определенно работает лучше, но его сложнее правильно реализовать.
Это асинхронно. Идея в том, что я отправляю req1, устанавливаю тайм-аут и, скажем, я читаю только половину сообщения (res1) за это время. Затем я намерен отказаться от него, поскольку будет отправлено новое сообщение (res1). Но мой async_read_some() все еще читает первый, верно? И я хочу снова прочитать в новый буфер. Но я, наверное, что-то неправильно понял, я совсем новичок в этом.
@ user680891 async_read_some() читает данные. Он не осознает, является ли он первым, вторым, третьим или кем-то еще. Он читает поток. Вам решать интерпретировать входящие байты, являются ли они все тем же сообщением или, возможно, уже следующим. Также я настоятельно рекомендую сбрасывать тайм-аут всякий раз, когда вы читаете сообщение. Различить, является ли это новым сообщением или продолжением предыдущего, может быть слишком сложно.
Спасибо. Я думаю, что начинаю видеть проблемы в моем понимании асинхронных протоколов.
Если соединение tcp перестает работать, вам, вероятно, нужно закрыть сокет, который прервет
read_some