boost::asio::async_read 不回调我的处理函数

Posted

技术标签:

【中文标题】boost::asio::async_read 不回调我的处理函数【英文标题】:boost::asio::async_read does not callback my handler function 【发布时间】:2017-01-08 13:40:10 【问题描述】:

我正在与boost::asio 合作,在客户端和服务器应用程序之间进行TCP 通信,这两个应用程序都是由我编写的。我最初是通过使用boost::asio::read 的同步数据读取来编写的。 sync_read 工作正常,只是在读取操作期间我无法这样做 socket.cancel。这已成为一个相当大的限制,因此 我现在正在尝试将我的同步读取转换为 async_read 机制

以下是我的同步读取机制,非常好。我读了2遍。首先获取包头,然后获取包数据,效果很好 ->

size_t Read_Data_Sync(std::vector<unsigned char> & msg_body) 
  //fetch the header
  MyMessageHeader msg_header;
  boost::system::error_code err_code;
  size_t bytes_received = boost::asio::read(socket, boost::asio::buffer(&msg_header, sizeof(msg_header)), err_code);

  if (bytes_received <= 0 || err_code)
    return 0;

  err_code.clear();
  msg_body.resize(msg_header.size);

  //fetch the body
  bytes_received = boost::asio::read(socket, boost::asio::buffer(msg_body), err_code);
  if (bytes_received <= 0 || error_code)
    return 0;

  return bytes_received;

上面的函数用于从客户端的thread 连续调用,我称之为阅读器线程like so ->

auto data_reader_thread = std::thread [this] 
    while(run_thread) 
        Read_Data_Sync();
    
;

以下是我如何更改它以使读取机制async ->

读取器线程保持不变,只是它现在调用另一个读取函数,我编写了该函数以async 方式读取数据

auto data_reader_thread = std::thread [this] 
    while(run_thread) 
        Read_Data_Async();
    
;

我已将msg_bodymsg_header 作为我班级的成员变量。更新后的逻辑是Read_Data_Async是从线程函数中连续调用的。 Read_Data_Async 调用 boost::asio::async_read 绑定 Handle_Read_Header 的地址作为回调,然后再次执行 boost::asio::async_read 以读取消息体,传递处理程序回调以接收 message_body

void Read_Data_Async() 

    //firstly read message header
    MyMessageHeader msg_header;
    boost::asio::async_read(socket, boost::asio::buffer(&msg_header, sizeof(msg_header)), boost::bind(&TCPSession::Handle_Read_Header, this,
                                                                                                             boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred));


void Handle_Read_Header(const boost::system::error_code & error, std::size_t bytes_transferred)

    //now read the message body
    if (!error && bytes_transferred > 0) 
        boost::asio::async_read(socket, boost::asio::buffer(msg_body), boost::bind(&TCPSession::Handle_Read_Body, this,
                                                                                                                 boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred));
    
    else 
        cout << "Error: " << error << "\n";
    



void Handle_Read_Body(const boost::system::error_code & error, std::size_t bytes_transferred)

    if (!error && bytes_transferred > 0) 
        // msg_body has the data read from socket
    
    else if (error != boost::asio::error::eof) 
        cout << "Error: " << error << "\n";
    

我现在面临的问题是回调Handle_Read_Header 永远不会被回调! 我在做什么有什么问题?我浏览了很多相关的帖子,比如this one 试图解决我的问题 问题,但该链接再次建议调用io.run,因为它是关于boost::asio::async_read_until 而不是boost::asio::async_read

我的上述逻辑对boost::asio::async_read 是否正确?我应该得到什么asio 来回调我的处理函数?

【问题讨论】:

哪个线程调用io_service对象上的run() 我的主线程调用io_service::run() & io_service 在主线程上。如何使用单独的阅读器线程进行这项工作? 【参考方案1】:

您必须在某处运行 io_service::run() ¹

实际上,执行异步 IO 的整个想法是您确实需要单独的线程来读取/写入:在单个线程上完全可以实现全双工。


¹或更复杂的循环,带有 run_one、poll 或 poll_one

【讨论】:

io_service::run() 在与服务器连接的主线程上被调用。我一定会在工作线程上调用读取,因为我的应用程序是一个不断快速更新数据的应用程序。因此我一定会有一个线程在循环中调用读取。如果没有连接,我是否也应该在我的阅读器线程中进行连接? 服务run 在没有完成处理程序时立即完成。确保在最后一个操作完成之前发布下一个操作。或使用io_service::work。该示例显示了所有这些是如何工作的 这不是很严格吗?我是否在主线程或其他线程上调用 io_service::run() 对 asio 有什么影响?如何在工作线程上连续调用 read 来完成这项工作?应该有人遇到过同样的问题。 @SegmentationFault 我没说在哪里运行服务。真的相反。是的,很多人面临着同样的选择。从样本开始 对不起,如果我误解了。我在主线程上做io_service.run,而我所有的读取都在一个工作线程上。这种设计不适用于async_read

以上是关于boost::asio::async_read 不回调我的处理函数的主要内容,如果未能解决你的问题,请参考以下文章

Boost::asio::async_read 不会在条件下停止

优雅地取消 boost::asio::async_read

boost::asio::async_read 无限循环,接收数据为零字节

如何在到达终止字符时返回 boost::asio::async_read

boost asio async_read中的随机EOF

boost::asio::async_read 在接收到完整的 Content-Length 之前接收 EOF