用boost.asio链接异步lambdas
Chaining asynchronous Lambdas with Boost.Asio?
我发现自己写的代码基本上是这样:
using boost::system::error_code;
socket.async_connect(endpoint, [&](error_code Error)
{
if (Error)
{
print_error(Error);
return;
}
// Read header
socket.async_read(socket, somebuffer, [&](error_code Error, std::size_t N)
{
if (Error)
{
print_error(Error);
return;
}
// Read actual data
socket.async_read(socket, somebuffer, [&](error_code Error, std::size_t N)
{
// Same here...
});
});
};
基本上,我在回调中嵌套回调,而逻辑很简单且"线性"。
是否有更优雅的写作方式,以便代码既是本地又是固定的?
一种优雅的解决方案是使用coroutines。BOOST.ASIO支持两种无stackless coroutines,它引入了一小部分伪关键字和堆叠的Coroutines,它们使用Boost.Coroutine。
无固定的Coroutines
stackless coroutines引入了一组伪关键字的预处理器宏,该预处理宏使用类似于Duff设备的技术实现开关语句。该文档详细介绍了每个关键字。
原始问题(连接 ->读取标题 ->读取主体)在用无stack coroutines实现时看起来类似于以下内容:
struct session
: boost::asio::coroutine
{
boost::asio::ip::tcp::socket socket_;
std::vector<char> buffer_;
// ...
void operator()(boost::system::error_code ec = boost::system::error_code(),
std::size_t length = 0)
{
// In this example we keep the error handling code in one place by
// hoisting it outside the coroutine. An alternative approach would be to
// check the value of ec after each yield for an asynchronous operation.
if (ec)
{
print_error(ec);
return;
}
// On reentering a coroutine, control jumps to the location of the last
// yield or fork. The argument to the "reenter" pseudo-keyword can be a
// pointer or reference to an object of type coroutine.
reenter (this)
{
// Asynchronously connect. When control resumes at the following line,
// the error and length parameters reflect the result of
// the asynchronous operation.
yield socket_.async_connect(endpoint_, *this);
// Loop until an error or shutdown occurs.
while (!shutdown_)
{
// Read header data. When control resumes at the following line,
// the error and length parameters reflect the result of
// the asynchronous operation.
buffer_.resize(fixed_header_size);
yield socket_.async_read(boost::asio::buffer(buffer_), *this);
// Received data. Extract the size of the body from the header.
std::size_t body_size = parse_header(buffer_, length);
// If there is no body size, then leave coroutine, as an invalid
// header was received.
if (!body_size) return;
// Read body data. When control resumes at the following line,
// the error and length parameters reflect the result of
// the asynchronous operation.
buffer_.resize(body_size);
yield socket_.async_read(boost::asio::buffer(buffer_), *this);
// Invoke the user callback to handle the body.
body_handler_(buffer_, length);
}
// Initiate graceful connection closure.
socket_.shutdown(tcp::socket::shutdown_both, ec);
} // end reenter
}
}
堆叠的coroutines
使用spawn()
函数创建堆叠式Coroutines。最初的问题可能看起来像以下内容,以备用coroutines实现:
boost::asio::spawn(io_service, [&](boost::asio::yield_context yield)
{
boost::system::error_code ec;
boost::asio::ip::tcp::socket socket(io_service);
// Asynchronously connect and suspend the coroutine. The coroutine will
// be resumed automatically when the operation completes.
socket.async_connect(endpoint, yield[ec]);
if (ec)
{
print_error(ec);
return;
}
// Loop until an error or shutdown occurs.
std::vector<char> buffer;
while (!shutdown)
{
// Read header data.
buffer.resize(fixed_header_size);
std::size_t bytes_transferred = socket.async_read(
boost::asio::buffer(buffer), yield[ec]);
if (ec)
{
print_error(ec);
return;
}
// Extract the size of the body from the header.
std::size_t body_size = parse_header(buffer, bytes_transferred);
// If there is no body size, then leave coroutine, as an invalid header
// was received.
if (!body_size) return;
// Read body data.
buffer.resize(body_size);
bytes_transferred =
socket.async_read(boost::asio::buffer(buffer), yield[ec]);
if (ec)
{
print_error(ec);
return;
}
// Invoke the user callback to handle the body.
body_handler_(buffer, length);
}
// Initiate graceful connection closure.
socket.shutdown(tcp::socket::shutdown_both, ec);
});
相关文章:
- 获取日期异步信号安全吗?如果在信号处理程序中使用,它会导致死锁吗
- 为什么在C++20中对lambdas使用"std::bind_front"
- 如何在C++中实现带有packaged_task的异步等待循环?
- 创建 Spdlog 异步文件记录器时遇到困难
- C ++异步键盘输入(标准方式)
- 在 gtkmm 中异步加载图像
- 带有 Boost.Beast 的异步读取标头
- 如何在 c++ 中异步调用静态方法?
- libcurl :C++处理多个异步请求
- 如何在C++上启动异步线程
- TCP 服务器的异步读取使用 boost::asio 打印客户端套接字发送的数据
- 增强 ASIO 和串行端口异步读取
- 使用 Qt5 SQL 进行异步数据库访问的策略
- 如何使用从处理程序调度的最终回调将响应异步返回给调用方on_read?
- C++中真正的异步文件 IO
- 提升::Asio 异步聊天客户端停止与服务器通信
- 在 c++ 托管和异步运行中调用 c# 可执行文件
- std::异步与非静态成员函数
- 我有一个关于C++提升的问题:: asio 和 std :: 异步
- 用boost.asio链接异步lambdas