繁体   English   中英

使用boost :: asio :: async_wait_until和boost :: asio :: streambuf

[英]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次

  • 在第一个调用中有一条线被抽入缓冲区
  • 在接下来的6个通话中没有
  • 下次通话中有6行
  • 接下来的10个没有数据
  • 下列10行...

我显然做错了什么,但这是什么?

async_read_until不能保证仅在第一个定界符之前进行读取。

由于底层实现的细节,它只会在大多数系统上“读取可用的内容”,如果streambuf包含定界符,它将返回。 其他数据将在streambuf中 而且,即使您还没有想到,也可能会返回EOF

请参阅背景, 直到在boost :: asio :: streambuf中使用字符串定界符为止

因此,在这里找到了问题。 该程序的工作方式是:

  1. 发送数据请求
  2. 启动async_read_until以读取端口上的数据。
  3. 启动async_wait ,这样我们就不会永远等待。
  4. 使用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_expiredsuccess 但是,如您所见,如果取消操作( op_canceled发生错误( error_out ),系统将退出。

问题是,当取消异步操作时( io_service::run_oneio_service::run_one deadline_timer::cancel() ),它将触发io_service::run_one拾取的事件,该事件会将switch语句评估的状态设置为op_canceled 这可能会使异步操作堆积在事件循环中。 一个简单的解决方法是在所有情况下仅将return语句注释掉,但successtimeout_expired除外。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM