如何使用 Boost.Asio 正确实现 async/await 语法

How to implement async/await syntax properly using Boost.Asio

我正在尝试使用 Boost.Asio 实现一些网络应用程序。我对多层回调有疑问。在其他原生支持async/await语法的语言中,我可以这样写我的逻辑

void do_send(args...) {
  if (!endpoint_resolved) {
    await resolve_async(...);  // results are stored in member variables
  }
  if (!connected) {
    await connect_async(...);
  }
  await send_async(...);
  await receive_async(...);
}

现在我必须使用多层回调来编写它

void do_send(args...) {
  if (!endpoint_resolved) {
    resolve_async(..., [captures...](args...) {
      if (!connected) {
        connect_async(..., [captures...](args...) {
          send_async(..., [captures...](args...) {
            receive_async(..., [captures...](args...) {
              // do something
            });  // receive_async
          });  // send_async
        });  // connect_async
      }
    });
  }
}

这很麻烦而且容易出错。另一种方法是使用 std::bind 将成员函数绑定为回调,但这并不能解决问题,因为无论哪种方式我都必须在回调中编写复杂的逻辑来确定下一步要做什么。

我想知道是否有更好的解决方案。 理想情况下,我希望以同步方式编写代码,同时我可以在任何 I/O 操作上异步 await

我也查了std::asyncstd::future等,但好像不符合我的情况

Boost.Asio 的 stackful coroutines would provide a good solution. Stackful coroutines allow for asynchronous code to be written in a manner that reads synchronous. One can create a stackful coroutine via the spawn 函数。在协程中,将 yield_context 作为处理程序传递给异步操作将启动操作并暂停协程。当异步操作完成时,协程将自动恢复。这是文档中的示例:

boost::asio::spawn(my_strand, do_echo);

// ...

void do_echo(boost::asio::yield_context yield)
{
  try
  {
    char data[128];
    for (;;)
    {
      std::size_t length =
        my_socket.async_read_some(
          boost::asio::buffer(data), yield);

      boost::asio::async_write(my_socket,
          boost::asio::buffer(data, length), yield);
    }
  }
  catch (std::exception& e)
  {
    // ...
  }
}