【问题标题】:How do I use a composed Asio operation with C++20 coroutines to return a value?如何将组合的 Asio 操作与 C++20 协程一起使用来返回值?
【发布时间】:2022-01-05 23:42:04
【问题描述】:

我有一个组合异步操作,它使用非加速 Asio 1.18.1 来解析并连接到主机和服务。

我希望它将它连接到的实际端点传递给完成令牌。现在没有。

#include <iostream>
#include <string_view>

#include "asio.hpp"

template <typename Token, typename Executor>
auto async_connect_to(Executor&& executor, asio::ip::tcp::socket& socket,
                      asio::ip::tcp::resolver& resolver, std::string_view host,
                      std::string_view service, Token&& token) {
  return asio::async_compose<Token, void()>(
      [&](auto& self) {
        co_spawn(
            executor,
            [&]() -> asio::awaitable<void> {
              auto results = co_await resolver.async_resolve(host, service, asio::use_awaitable);
              auto endpoint = co_await asio::async_connect(socket, results, asio::use_awaitable);
              self.complete();
              co_return;
            },
            asio::detached);
      },
      token, executor);
}

int main(int argc, char* argv[]) {
  if (argc != 3) {
    std::cerr << "Usage: client <host> <port>\n";
    return 1;
  }

  asio::io_context io_context;
  asio::ip::tcp::socket socket(io_context);
  asio::ip::tcp::resolver resolver(io_context);

  async_connect_to(io_context, socket, resolver, argv[1], argv[2],
                   [](asio::ip::tcp::endpoint endpoint = {}) {
                     std::cout << "connected to: " << endpoint << "\n";
                   });

  try {
    io_context.run();
  } catch (std::exception& e) {
    std::cerr << "error: " << e.what() << "\n";
    return 1;
  }

  return 0;
}

因为我在做self.complete()main 中的完成处理程序实际上从未真正获得我们连接的端点,所以它是默认的。

  1. 如何从这个组合的异步操作中实际返回一个值?
  2. 如何改进错误处理,以便完成处理程序可以采用签名(error_code, tcp::endpoint) 而不仅仅是(tcp::endpoint),即它的工作方式与内置异步操作相同? (我相信在回答第一个问题后这很简单)

docs 没有提供 async_compose 和协程的示例,也没有从 co_spawn 返回值。

【问题讨论】:

    标签: c++ boost-asio c++20 coroutine


    【解决方案1】:

    我以为我已经尝试过了,但只需更改 async_compose 模板参数和 self.complete 的签名即可。

    对于错误,您似乎需要显式捕获system_error,将其作为error_code 传递给完成处理程序,它可以传递给用户的完成处理程序或转换回@987654325 @ 带有 use_future 令牌之类的东西。

    template <typename Token, typename Executor>
    auto async_connect_to(Executor&& executor, asio::ip::tcp::socket& socket,
                          asio::ip::tcp::resolver& resolver, std::string_view host,
                          std::string_view service, Token&& token) {
      return asio::async_compose<Token,
                                 void(std::error_code, asio::ip::tcp::endpoint)>(
          [&](auto& self) {
            co_spawn(
                executor,
                [&]() -> asio::awaitable<void> {
                  try {
                    auto results = co_await resolver.async_resolve(
                        host, service, asio::use_awaitable);
                    auto endpoint = co_await asio::async_connect(
                        socket, results, asio::use_awaitable);
                    self.complete({}, endpoint);
                  } catch (std::system_error& e) {
                    self.complete(e.code(), {});
                  }
                  co_return;
                },
                asio::detached);
          },
          token, executor);
    }
    

    这似乎可以正常工作:

      async_connect_to(
          io_context, socket, resolver, argv[1], argv[2],
          [](std::error_code ec, asio::ip::tcp::endpoint endpoint = {}) {
            if (ec) {
              std::cout << "error: " << ec.message() << "\n";
            } else {
              std::cout << "connected to: " << endpoint << "\n";
            }
          });
    

    但由于某种原因,当我使用 use_future 作为完成标记时,当前出现了段错误。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-07-08
      • 2020-07-11
      • 1970-01-01
      • 1970-01-01
      • 2021-05-06
      • 2021-12-27
      • 2023-03-03
      相关资源
      最近更新 更多