Using boost::asio::async_wait_until with boost::asio::stream
Using boost::asio::async_wait_until with boost::asio::streambuf
我目前正在开发一个应用程序,用于使用串行通信与设备进行通信。 为此,我正在使用提升库basic_serial_port。 现在,我只是尝试从设备读取,并使用async_wait_until
函数以及deadline_timer
类的async_wait
。 设置读取和等待的代码如下所示:
async_read_until(port,readData,io_params.delim,
boost::bind(&SerialComm::readCompleted,
this,boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred));
timer.expires_from_now(boost::posix_time::seconds(1));
timer.async_wait(boost::bind(&SerialComm::timeoutExpired,this,
boost::asio::placeholders::error));
async_read_until
上的回调看起来像
void SerialComm::readCompleted(const boost::system::error_code& error,
const size_t bytesTransferred){
if (!error){
wait_result = success;
bytes_transferred = bytesTransferred;
}
else {
if (error.value() != 125) wait_result = error_out;
else wait_result = op_canceled;
cout << "Port handler called with error code " + to_string(error.value()) << endl;
}
}
并且以下代码在成功读取时触发
string msg;
getline(istream(&readData), msg, 'r');
boost::trim_right_if(msg, boost::is_any_of("r"));
对于此设备,所有消息都以回车符终止,因此在async_read_until
中指定回车符应检索单个消息。但是,我所看到的是,当处理程序被触发时,新数据不一定输入到缓冲区中。 所以,我可能会看到的是,如果处理程序被触发 20 倍
- 在第一次调用中将一行泵入缓冲区
- 在接下来的 6 次调用中无
- 下次通话 6 行
- 接下来的 10 年没有数据
- 以下 10 行 ...
我显然没有做正确的事情,但它是什么?
async_read_until
不保证它只读取到第一个分隔符。
由于底层实现细节,它只会在大多数系统上"读取可用内容",如果 streambuf 包含分隔符,它将返回。其他数据将在 streambuf 中。此外,即使您还没有预料到,EOF也可能被退回。
请参阅背景 阅读直到 boost::asio::streambuf 中的字符串分隔符
所以,在这里找到了问题。 该程序旨在工作的方式是它应该
- 发送数据请求
- 启动
async_read_until
以读取端口上的数据。 - 开始一个
async_wait
,这样我们就不会永远等待。 - 使用
io_service::run_one
等待超时或读取成功。
第四步的代码如下所示:
for (;;){
// This blocks until an event on io_service_ is set.
n_handlers = io_service_.run_one();
// Brackets in success case limit scope of new variables
switch(wait_result){
case success:{
char c_[1024];
//string msg;
string delims = "r";
std::string msg{buffers_begin(readData.data()), buffers_begin(readData.data()) + bytes_transferred- delims.size()};
// Consume through the first delimiter.
readData.consume(bytes_transferred);
data_out = msg;
cout << msg << endl;
data_handler(msg);
return data_out;
}
case timeout_expired:
//Set up for wait and read.
wait_result = in_progress;
cout << "Time is up..." << endl;
return data_out;
break;
case error_out:
cout << "Error out..." << endl;
return data_out;
break ;
case op_canceled:
return data_out;
break;
case in_progress:
cout << "In progress..." << endl;
break;
}
}
只有两种情况应触发循环的退出 -timeout_expired
和success
。 但是,如您所见,如果操作被取消(op_canceled
)或出现错误(error_out
),系统将退出。
问题是当异步操作被取消时(即deadline_timer::cancel()
) 它将触发io_service::run_one
选取的事件,该事件将 switch 语句评估的状态设置为op_canceled
。 这可能会使异步操作在事件循环中堆叠。 简单的解决方法是在除success
和timeout_expired
之外的所有情况下都注释掉 return 语句。
- 理解boost::asio-async_read在无需读取内容时的行为
- C++Boost Asio Pool线程,带有lambda函数和传递引用变量
- boost::asio::steady_timer()与sleep()我应该使用哪一个
- boost::asio如何生成多个协同程序,然后加入它们
- 从 Boost ASIO 获取 epoll 描述符 io_service对象
- 如何在 Boost.Asio 中使用 Zero-copy sendmsg/receive
- C++ Boost::asio串行通信与Arduino无法写入
- 如何使用 Boost Asio 在 Android 上获取我的本地 udp IP 地址?
- boost::asio UDP 广播客户端仅接收"fast"数据包
- 执行时使用 boost::asio::d eadline_timer 时出错
- Boost.Asio/OpenSSL HTTPS GET certificate trouble
- C++ boost::asio::ip::tcp::acceptor 有时不接受连接器?
- boost::asio data owning `ConstBufferSequence`
- 如何替换此示例代码片段中已弃用的handler_type_t或 boost::asio::handler_type?
- 将 boost 序列化对象的 asio::streambuf 表示转换为 Beast 的 DynamicBody req.body()
- 如何将boost::asio::d eadline_timer 与Qt一起使用?
- 将更高的优先级设置为 boost::asio 线程处理进程
- Async_read_until限制读取的字节大小(Boost::asio)
- Boost Asio - boost::bind 导致程序崩溃
- 使用Asio(Boost)通过网络发送灵活的数据量