[英]Using boost::asio::async_wait_until with boost::asio::streambuf
我有一个当前正在开发的应用程序,用于使用串行通信与设备进行通信。 为此,我使用了增强库basic_serial_port。 现在,我只是尝试从设备读取数据,并且正在使用async_wait_until
函数,再加上deadline_timer
async_wait
类中的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
指定回车async_read_until
应检索一条消息。 但是,我看到的是,在触发处理程序时,新数据不一定会输入到缓冲区中。 所以,我可能会看到的是,如果处理程序被触发20次
我显然做错了什么,但这是什么?
async_read_until
不能保证仅在第一个定界符之前进行读取。
由于底层实现的细节,它只会在大多数系统上“读取可用的内容”,如果streambuf包含定界符,它将返回。 其他数据将在streambuf中 。 而且,即使您还没有想到,也可能会返回EOF 。
因此,在这里找到了问题。 该程序的工作方式是:
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
),系统将退出。
问题是,当取消异步操作时( io_service::run_one
, io_service::run_one
deadline_timer::cancel()
),它将触发io_service::run_one
拾取的事件,该事件会将switch语句评估的状态设置为op_canceled
。 这可能会使异步操作堆积在事件循环中。 一个简单的解决方法是在所有情况下仅将return语句注释掉,但success
和timeout_expired
除外。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.