【发布时间】:2021-04-16 22:43:33
【问题描述】:
背景
我刚开始使用 Boost::Asio 库,无法获得我想要的行为。我正在尝试为自定义硬件解决方案实施一些网络通信。我们使用的通信协议栈严重依赖 Boost::Asio 异步方法,我不认为它是完全线程安全的。
我已成功实现发送,但在尝试设置等待接收时遇到问题。我发现大多数boost::asio examples 都依赖套接字行为来使用socket_.async_read_some() 或其他类似功能实现异步等待。然而这对我们不起作用,因为我们的硬件解决方案需要直接调用驱动程序函数而不是使用套接字。
应用程序使用io_service 传递给boost::asio::generic::raw_protocol::socket 以及其他类。
使用套接字的协议栈示例代码
这是来自协议栈的示例代码。在 RawSocketLink 的构造函数中调用了do_receive()。
void RawSocketLink::do_receive()
{
namespace sph = std::placeholders;
socket_.async_receive_from(
boost::asio::buffer(receive_buffer_), receive_endpoint_,
std::bind(&RawSocketLink::on_read, this, sph::_1, sph::_2));
}
void RawSocketLink::on_read(const boost::system::error_code& ec, std::size_t read_bytes)
{
if (!ec) {
// Do something with received data...
do_receive();
}
}
我们之前没有协议栈的接收代码
在实现堆栈之前,我们一直在使用线程库为发送和接收创建单独的线程。接收方法如下所示。大多数情况下,它依赖于从硬件驱动程序调用receive_data() 函数并等待它返回。这是一个阻塞调用,但需要返回数据。
void NetworkAdapter::Receive() {
uint8_t temp_rx_buffer[2048];
rc_t rc;
socket_t *socket_ptr;
receive_params_t rx_params;
size_t rx_buffer_size;
char str[100];
socket_ptr = network_if[0];
while (1) {
rx_buffer_size = sizeof(temp_rx_buffer);
// Wait until receive_data returns then process
rc = receive_data(socket_ptr,
temp_rx_buffer,
&rx_buffer_size,
&rx_params,
WAIT_FOREVER);
if (rc_error(rc)) {
(void)fprintf(stderr, "Receive failed");
continue;
}
// Do something with received packet ....
}
return;
}
请注意,此代码中的 socket_t 指针不与 Boost::Asio 的 TCP/UDP 套接字相同。
异步接收的当前实现
这是我当前的代码,我需要帮助。我不确定如何使用 boost::asio 方法等待 receive_data 返回。我们正在尝试复制socket.async_read_from() 的行为。 NetworkAdapter 可以访问io_service。
void NetworkAdapter::do_receive() {
rc_t rc;
socket_t *socket_ptr;
receive_params_t rx_params;
size_t rx_buffer_size;
socket_ptr = network_if[0];
rx_buffer_size = receive_buffer_.size();
// What do I put here to await for this to return asynchronously?
rc = receive_data(socket_ptr, receive_buffer_.data(), &rx_buffer_size, &rx_params, ATLK_WAIT_FOREVER);
on_read(rc, rx_buffer_size, rx_params);
}
void NetworkAdapter::on_read(const rc_t &rc, std::size_t read_bytes, const receive_params_t &rx_params) {
if (!rc) {
// Do something with received data...
} else {
LOG(ERROR) << "Packet receieve failure";
}
do_receive();
}
总结
如何使用 boost::asio async/await 函数来等待函数返回?特别是我想复制socket.async_receive_from() 的行为,但使用函数而不是套接字。
*由于数据保护要求,某些函数名称和类型已更改。
【问题讨论】:
-
你在使用协程吗?如果是这样,什么编译器/版本?如果不是,
async/await是什么意思?使用阻塞 API 实现async_风格的函数是先进的:您需要实现一个自定义服务,除非您对 Asio 编程和内部非常有经验,否则您不应该学习这一点。有一些快捷方式,但简而言之,除了使用线程+例如额外的代码之外,它们不会为您带来任何好处。承诺 -
@sehe 我们有一个所有类都可以访问的 io_service。 io_service.run() 在主函数结束时调用。在 NetworkAdapter 的构造函数中调用了
do_receive()函数。 -
@sehe 我不是自愿学习这个的,我们是被我们使用的协议栈和硬件 api 强迫进入的。我们正在使用 gcc 交叉编译来武装。
-
我能想到的最简单的集成方法是将您的任务推送到一个额外的线程并从那里将完成处理程序发布到 io_service。
-
@sehe 就像在单独的线程中运行
do_receive(),然后在io_service 线程上使用post调用on_read()?你有没有机会举例说明那会是什么样子?我查看了 boost 文档中的帖子,但不知道如何将其应用于我的情况。
标签: c++ boost async-await boost-asio