如果不调用读取处理程序,是否有办法知道async_read函数中传输的字节数?

时间:2019-08-01 00:13:02

标签: c++ boost boost-asio

我已对以下 DoRead 函数进行了编码,该函数从打开的串行端口读取数据,并且除以下事项外,它均按预期工作:

  • 如果在读取完成之前超时,则不会调用任何读取处理程序,并且此时我无法获取读取的字节数。

这是我的代码:

std::size_t wxSerialPort::DoRead(std::string& str, const int timeout)
{
    m_bytes_transferred_read = 0;

    boost::asio::async_read(m_serialPort, boost::asio::buffer(str),
                            std::bind(&wxSerialPort::AsyncReadHandler, this,
                                      std::placeholders::_1, std::placeholders::_2));

    m_io_context.restart();

    if (timeout == wxTIMEOUT_INFINITE)
    {
        m_io_context.run_until(std::chrono::steady_clock::time_point::max());
    }
    else
    {
        m_io_context.run_for(std::chrono::milliseconds(timeout));
    }

    return m_bytes_transferred_read; // At this point I always get 0 bytes read.
}

void wxSerialPort::AsyncReadHandler(const boost::system::error_code& error, std::size_t bytes_transferred)
{
    m_bytes_transferred_read = bytes_transferred;
}

请记住,任何以 m _ 开头的变量都是成员变量。

但是,如果我为该函数提供了一个小的缓冲区,那么读取处理程序将在超时之前被调用,并且我会获得读取的实际字节数。

谢谢。

2 个答案:

答案 0 :(得分:0)

听起来您需要致电async_read_some而不是async_read

async_read函数确保:在异步操作完成之前已读取请求的数据量,即,在调用读取处理程序之前,它需要足够的数据来填充缓冲区。

无论何时缓冲区已满,basic_serial_port::async_read_some方法都会调用read处理程序。

因此,只需将对async_read的调用替换为:

m_serialPort.async_read_some(boost::asio::buffer(str),
                        std::bind(&wxSerialPort::AsyncReadHandler, this,
                                  std::placeholders::_1, std::placeholders::_2));

答案 1 :(得分:0)

事实证明,boost-asio-按设计 -,不会为任何 io_context :: run_for 调用任何IO处理程序 io_context :: run_one_for io_context :: run_until io_context :: run_one_until 起作用。

解决此问题的方法是提供我们自己的 wait handler cancel basic_serial_port :: cancel )所有异步操作与该等待处理程序中的串行端口相关联,这将依次以 boost :: asio :: error :: operation_aborted 错误代码触发读取处理程序。

结果代码如下:

std::size_t wxSerialPort::DoRead(std::string& str, const int timeout)
{
    m_bytes_transferred_read = 0;

    if (timeout == wxTIMEOUT_INFINITE)
    {
        m_timer.expires_at(std::chrono::steady_clock::time_point::max());
    }
    else
    {
        m_timer.expires_from_now(std::chrono::milliseconds(timeout));
    }

    m_timer.async_wait(std::bind(&wxSerialPort::AsyncWaitHandler, this,
                                 std::placeholders::_1));

    boost::asio::async_read(m_serialPort, boost::asio::buffer(str),
                            std::bind(&wxSerialPort::AsyncReadHandler, this,
                                      std::placeholders::_1, std::placeholders::_2));

    m_io_context.restart();
    m_io_context.run();

    return m_bytes_transferred_read;
}

void wxSerialPort::AsyncReadHandler(const boost::system::error_code& error, std::size_t bytes_transferred)
{
    if (error != boost::asio::error::operation_aborted)
    {
        m_timer.cancel();
    }

    m_bytes_transferred_read = bytes_transferred;
}

void wxSerialPort::AsyncWaitHandler(const boost::system::error_code& error)
{
    if (error != boost::asio::error::operation_aborted)
    {
        m_serialPort.cancel();
    }
}

谢谢。