Так что я боролся с созданием некоторого слоя абстракции над Boost.Asio.Есть определенные пакеты операций, которые я хочу обработать атомарно, например tcp::resolver::resolve()
и asio::connect()
.Если я использую асинхронную версию обоих, код становится очень неприятным, потому что мне приходится «цеплять» обратные вызовы.По сути:
- Пользователь вызывает мой
Connect()
метод-обертку, который принимает хост и служебную строку, а также обеспечивает обратный вызов, который вызывается, когда соединение установлено. - Вызвать
resolver::async_resolve()
, используя параметры строки host и service.Привязать обратный вызов пользователя к обратному вызову для разрешения (для передачи обратного вызова, который будет вызван после подключения) - Из обратного вызова разрешения, в случае успеха вызовите
asio::async_connect()
.Снова, свяжите обратный вызов пользователя с обратным вызовом подключения. - В обратном вызове подключения, в случае успеха, вызовите обратный вызов пользователя
Либо это неприятно из-за тонны вложенных лямбд,или неприятно, потому что функции разделены, и теперь у меня есть класс, загруженный с шаблоном.Мне кажется, было бы намного проще просто сделать что-то подобное (не компилировать, так что пока просто воспринимайте это как псевдокод):
using ConnectCallback = std::function<void(std::shared_ptr<tcp::socket>)>;
void Connect(std::string const& host, std::string const& service, ConnectCallback cb)
{
std::thread{[this, host, service, cb{std::move(cb)}]
{
std::shared_ptr<tcp::socket> socket;
try
{
tcp::resolver r{m_context};
auto endpoints = r.resolve(host, service);
socket = std::make_shared<tcp::socket>(m_context);
asio::connect(*socket, endpoints);
}
catch (std::exception const&)
{
// either resolve or connect failed / timed out
}
cb(std::move(socket));
}}.detach();
}
Для меня это намного проще, по крайней мередля инициирования соединения, потому что мне не нужно беспокоиться о таком количестве обратных вызовов.Единственным недостатком является то, что я не уверен, как обрабатывать сценарии тайм-аута, используя этот метод.Все решения, связанные с тайм-аутами, которые я нашел в Google, требуют использования методов async_
.
Рекомендуется ли действовать таким образом или я должен придерживаться асинхронных методов?И если последнее, какие методы я могу использовать, чтобы упростить шаблон цепочки обратных вызовов?