C++ 使用Boost::asio触发写操作

C++ 使用Boost::asio触发写操作,c++,boost,asynchronous,boost-asio,C++,Boost,Asynchronous,Boost Asio,我有一些软件,我想做一个TCP客户端。我不知道这是否是最好的体系结构,但在我的软件中,我产生了一个线程,将用于网络I/O。如果有更好的体系结构,我将感谢一些指针和建议 两个线程都引用boost::asio::io_服务对象和封装套接字对象的会话对象。sesson对象大致如下所示: class Session { public: Session( boost::asio::io_service & io_service, std::string const

我有一些软件,我想做一个TCP客户端。我不知道这是否是最好的体系结构,但在我的软件中,我产生了一个线程,将用于网络I/O。如果有更好的体系结构,我将感谢一些指针和建议

两个线程都引用boost::asio::io_服务对象和封装套接字对象的会话对象。sesson对象大致如下所示:

  class Session
  {
  public:

  Session(
    boost::asio::io_service & io_service,
    std::string const & ip_address,
    std::string const & port)
  : io_service_(io_service),
    resolver_(io_service),
    socket_(io_service),
    ip_address_(ip_address),
    port_(port),
  {}

  virtual void start();
  virtual ~Session();
  virtual void stop();
  void write(std::string const & msg);

  void handle_resolve(
    const boost::system::error_code & error,
    boost::asio::ip::tcp::resolver::iterator endpoint_itr);

  void handle_connect(
    const boost::system::error_code & error,
    boost::asio::ip::tcp::resolver::iterator endpoint_itr);

  void handle_close();
  void handle_write(const boost::system::error_code & error);

private:
  boost::asio::io_service & io_service_;
  boost::asio::ip::tcp::resolver resolver_;
  boost::asio::ip::tcp::socket socket_;
  std::string ip_address_;
  std::string port_;
};
    void Session::start()
    {
      typedef boost::asio::ip::tcp tcp;

      tcp::resolver::query query(
          tcp::v4(),
          ip_address_,
          port_);  

      resolver_.async_resolve(
          query,
          boost::bind(
              &Session::handle_resolve,
              this,
              boost::asio::placeholders::error,
              boost::asio::placeholders::iterator));

      while(1){ // improve this later
        io_service_.run();
      }
    }
在I/O线程运行循环中,调用连接到服务器的会话对象的start()方法。(顺便说一句,这很有效)。然后,线程位于一个循环中,调用I/O服务对象[io_service_uu.run()]上的run()方法来触发事件

当主线程想要发送数据时,它调用会话的write()方法,会话对象调用boost::async_write,其中包含要写入的数据,然后调用作为会话对象成员的回调方法(handle_write)

虽然我有连接到服务器的I/O线程,但无法触发handle_write方法。我已经验证了主线程正在调用会话对象并在套接字上执行async_write()。只是回调从未被触发。我也看不到服务器端的任何数据,也看不到tcpdump的连线数据

知道我的问题在哪里吗?有没有更好的方法来组织架构?最重要的是,我不想阻止主线程执行I/O

以下是从主线程生成io线程的代码(对于间隔表示歉意):

解析程序的回调:

    void Session::handle_resolve(
        const boost::system::error_code & error,
        boost::asio::ip::tcp::resolver::iterator endpoint_itr)
    {
      if (!error)
      {
        boost::asio::ip::tcp::endpoint endpoint = *endpoint_itr;
        socket_.async_connect(
            endpoint,
            boost::bind(
              &Session::handle_connect,
              this,
              boost::asio::placeholders::error,
              ++endpoint_itr));
      }
      else
      {
        std::cerr << "Failed to resolve\n";
        std::cerr << "Error: " << error.message() << std::endl;
      }
    }
void Session::handle\u resolve(
常量boost::system::error\u代码和错误,
boost::asio::ip::tcp::解析器::迭代器端点(itr)
{
如果(!错误)
{
boost::asio::ip::tcp::endpoint=*endpoint\u itr;
套接字异步连接(
终点,
boost::bind(
&会话::handle_connect,
这
boost::asio::占位符::错误,
++终点(itr);
}
其他的
{

std::cerr看起来您的io服务在连接后将失去工作,之后您只需再次调用io_服务::run?看起来在while循环中正在调用run,但是我看不到在任何地方调用reset。在再次调用同一io_服务之前,您需要调用io::service::reset


从结构上讲,最好添加到io_服务,这样就不需要在循环中调用它,一旦调用io_服务::stop,运行就会退出。

这部分代码

boost::asio::io_service io_service;
boost::shared_ptr<Session> session_ptr;
boost::thread io_thread;
....
session_ptr.reset(
  new Session::Session(
            io_service,
            std::string("127.0.0.1"),
            std::string("17001")));

// spawn new thread for the network I/O endpoint
io_thread = boost::thread(
  boost::bind(
    &Session::start,
    session_ptr_.get()));
如果您的代码基于该示例,您应该注意,
io_服务
始终在
main()
的作用域内。作为拉尔夫,您的
io_服务
也可能在连接处理程序之后没有工作可做,这就是为什么您在循环内部将其笨拙地调用
run()

while(1){ // improve this later
  io_service_.run();
}

请再次注意,该示例没有这样做。您需要在连接处理程序内启动另一个异步操作,根据应用程序的需要执行读或写操作。

我们可以查看start()、write()、handle_connect()和handle_write()的代码吗函数?您的示例不完整,请发布更多代码。以您所描述的方式使用asio非常常见,一个主线程和一个调用io_服务事件循环的第二个线程。根据请求添加了代码。我基本上从HTTP客户端示例中获取了大部分内容。您更新的问题仍然不完整,我们需要查看
会话n
类定义。对此很抱歉,希望这将提供所需的所有信息。谢谢。+1注意到连接处理程序之后,
io_服务将无法工作。啊,我明白了,我没有意识到我需要调用reset。工作情况如何?当我的客户端空闲并等待事情发生时(例如,等待来自主线程的事件或等待来自服务器的命令,我是否应该发布读取以保持io_服务有效?通过让io_服务工作,您不需要执行任何未完成的异步操作,例如读取。run方法只会在调用stop方法后返回。我想我理解。我会读取,写入一些数据,当读取回调被触发时,我可以发布另一个读取。这将使io_服务忙于工作,对吗?@Dr yes,你已经知道了。这是异步设计的优雅之处。处理程序排队等待额外的工作,保持
io_服务
循环处于活动状态。+1,很好地发现,没有看到io_服务ce超出范围(除非OP正在连接线程)那么,I/O服务是否应该是会话对象的一部分?@Ralf,是的,主线程正在线程上连接。它本身是一个基于事件的线程。@Dr
io\U服务
如果在线程的生命周期内保持在作用域内,则不需要成为
会话
对象的成员。
    void Session::write(
        std::string const & msg)
    {
      std::cout << "Write: " << msg << std::endl;
      boost::asio::async_write(
          socket_,
          boost::asio::buffer(
              msg.c_str(),
              msg.length()),
          boost::bind(
              &Session::handle_write,
              this,
              boost::asio::placeholders::error));     
    }
    void Session::handle_write(
        const boost::system::error_code & error)
    {
      if (error)
      {
         std::cout << "Write complete with errors !!!\n";
      }
      else
      {
         std::cout << "Write complete with no errors\n";
      }        
    }
boost::asio::io_service io_service;
boost::shared_ptr<Session> session_ptr;
boost::thread io_thread;
....
session_ptr.reset(
  new Session::Session(
            io_service,
            std::string("127.0.0.1"),
            std::string("17001")));

// spawn new thread for the network I/O endpoint
io_thread = boost::thread(
  boost::bind(
    &Session::start,
    session_ptr_.get()));
samm@macmini ~> grep -C 2 noncopyable  /usr/include/boost/asio/io_service.hpp 
#include <boost/asio/detail/epoll_reactor_fwd.hpp>
#include <boost/asio/detail/kqueue_reactor_fwd.hpp>
#include <boost/asio/detail/noncopyable.hpp>
#include <boost/asio/detail/select_reactor_fwd.hpp>
#include <boost/asio/detail/service_registry_fwd.hpp>
--
 */
class io_service
  : private noncopyable
{
private:
--
/// Class used to uniquely identify a service.
class io_service::id
  : private noncopyable
{
public:
--
/// Base class for all io_service services.
class io_service::service
  : private noncopyable
{
public:
while(1){ // improve this later
  io_service_.run();
}