Boost io_服务对象工作机制

Boost io_服务对象工作机制,boost,boost-asio,Boost,Boost Asio,我对io_服务对象的工作机制感到困惑。我的理解是,有一个队列与io_服务对象相关联,如果任何异步调用都会在队列中添加一个项,那么当调用io_service.run_时,一个异步调用将运行并从队列中退出。如果队列为空,io_service.run_one在添加新调用之前不会执行任何操作。我从boost示例中组织了一些代码,但似乎我的理解是错误的 #include <boost/asio/connect.hpp> #include <boost/asio/io_service.hp

我对io_服务对象的工作机制感到困惑。我的理解是,有一个队列与io_服务对象相关联,如果任何异步调用都会在队列中添加一个项,那么当调用io_service.run_时,一个异步调用将运行并从队列中退出。如果队列为空,io_service.run_one在添加新调用之前不会执行任何操作。我从boost示例中组织了一些代码,但似乎我的理解是错误的

#include <boost/asio/connect.hpp>
#include <boost/asio/io_service.hpp>
#include <boost/asio/ip/tcp.hpp>
#include <boost/system/system_error.hpp>
#include <boost/asio/write.hpp>
#include <cstdlib>
#include <iostream>
#include <string>
#include <boost/bind.hpp>
using boost::asio::deadline_timer;
using boost::asio::ip::tcp;

class client
{
public:
  client()
    : socket_(io_service_)
  {
  }

  void connect_handler(const boost::system::error_code& error,boost::system::error_code *er)
  {
      std::cerr<<"connect handler"<<std::endl;
      *er = error;
      std::cerr<<error<<std::endl;
  }

  void connect(const std::string& host, const std::string& service)
  {
    tcp::resolver::query query(host, service);
    tcp::resolver::iterator iter = tcp::resolver(io_service_).resolve(query);
    std::cerr<<"connect start"<<std::endl;

    boost::system::error_code ec = boost::asio::error::would_block;
    boost::asio::async_connect(socket_, iter, bind(&client::connect_handler,this,_1,&ec));

    do
    {io_service_.run_one();
    }while (ec == boost::asio::error::would_block);
    //io_service_.reset();  // The write async will be stuck without this reset call.
    std::cerr<<"connect done"<<std::endl;
    if (ec || !socket_.is_open())
      throw boost::system::system_error(
          ec ? ec : boost::asio::error::operation_aborted);
  }

  void write_handler(const boost::system::error_code& error, std::size_t size,boost::system::error_code* er )
  {
      std::cerr<<"write handler "<<std::endl;
      *er=error;
      std::cerr<<error<<std::endl;
  }

  void write_line(const std::string& line)
  {
    std::cerr<<"write start"<<std::endl;
    std::string data = line + "\n";
    boost::system::error_code ec = boost::asio::error::would_block;    
    boost::asio::async_write(socket_, boost::asio::buffer(data), bind(&client::write_handler,this,_1,_2,&ec));
    do
    {
        io_service_.run_one();     
    }while (ec == boost::asio::error::would_block);
    std::cerr<<"write done";
    if (ec)
      throw boost::system::system_error(ec);
  }

private:
  boost::asio::io_service io_service_;
  tcp::socket socket_;
};

int main()
{
  try
  {
    client c,d;
    c.connect("172.217.6.36", "80");// google IP.
    c.write_line("example");
  }
  catch (std::exception& e)
  {
    std::cerr << "Exception: " << e.what() << "\n";
  }

  return 0;
}
但现实是

Start
     | 
async_connect ----> add one item in io_service queue 
     |
     |
io_serivce.run_one() ------> dequeue the async_connect call back from io_serivce queue 
     |
     |
connect_handler --------> connect_handler called change the ec value
     |
     |
async_write ----------> add one item in io_service queue.
     |
     |
io_service.run_one()------------>stuck here in the while loop forever, the async_write handler is never be called the ec is never be changed. 
Sehe告诉我需要调用io_service.reset,我不明白为什么需要调用io_service.reset?原版不使用此调用,它工作正常。在重置调用工作时:

   Start
     | 
async_connect ----> add one item in io_service queue 
     |
     |
io_serivce.run_one() ------> dequeue the async_connect call back from io_serivce queue 
     |
     |
connect_handler --------> connect_handler called change the ec value
     |
     |
io_service.reset() --------> reset the io service.
     |
     |
async_write ----------> add one item in io_service queue.
     |
     |
io_service.run_one()------------>dequeue the async_write call back from io_serivce queue  
     |
     |
write_handler()----------------->write handler called and change the ec value
     |
   Done

原始示例使用截止时间计时器,该计时器位于连续的
async\u等待链中。这意味着
io_服务
永远不会耗尽工作

就这样。完全不同。如果您让服务无法工作,
run.*
将返回,您需要调用
reset()
,然后才能再次使用
io\u服务

另见



在前面的回答中,我给出了几种更好的方法,可以使用同步调用,也可以使用异步调用。

Hi Sehe,谢谢你的回答,你帮了我很多:),我写这篇文章是想更好地了解io_服务,你在我上一篇文章中的回答告诉了我正确的方法。有一件事我仍然不明白为什么io_服务会停止工作?我的理解是,async_connect和async_write两者都可以使io_服务队列不为空,但为什么在这种情况下async_connect可以工作,而async_write不能,并使io_服务无法工作?这就是它的设计方式,从定义上看是这样的。Async_connect还导致服务无法正常工作(显然)。这就是为什么你会发现下一步的操作。Sehe,谢谢你的回答,但我仍然感到困惑,让我简化我的问题。为什么可以调用async_connect回调,但在没有reset()的情况下永远不会调用async_write回调?从代码的角度来看,他们使用了完全相同的例程:设置ec-->call async function-->while loop来检查ec是否调用了回调。因为如果没有重置,工作永远不会被安排。另一次:它不是导致服务停止的
async\u write
。它是
async\u connect
导致它停止的(即使您无法判断,除非您检查
run()
run\u one()
的返回值)
   Start
     | 
async_connect ----> add one item in io_service queue 
     |
     |
io_serivce.run_one() ------> dequeue the async_connect call back from io_serivce queue 
     |
     |
connect_handler --------> connect_handler called change the ec value
     |
     |
io_service.reset() --------> reset the io service.
     |
     |
async_write ----------> add one item in io_service queue.
     |
     |
io_service.run_one()------------>dequeue the async_write call back from io_serivce queue  
     |
     |
write_handler()----------------->write handler called and change the ec value
     |
   Done