Boost :: asio :: async_write,只调用一次处理程序

时间:2013-12-01 20:07:04

标签: c++ boost-asio

我是boost :: asio的新手,我遇到了问题。我正在编写客户端,将一些命令发送到服务器。我用boost :: asio :: async_write发送命令,我希望每次发送命令时都会调用handler。实际上只有在第一次发送时才会看到该处理程序被调用。我的客户看起来像这样:

Client::Client(boost::asio::io_service & p_ioService,
           boost::asio::ip::tcp::endpoint p_endpoint)
 : io_service(p_ioService), endpoint(p_endpoint), socket(p_ioService)
{
   socket.connect(endpoint); 
}
Client::~Client()
{
    socket.close();
}
void Client::sendCommand(const string & p_command)
{
    boost::asio::async_write(socket,boost::asio::buffer(p_command), 
                              boost::bind(&Client::onSendingFinished,this, _1, _2));
    io_service.run();
}
void Client::onSendingFinished(const boost::system::error_code& ec, std::size_t    bytes_transferred)
{
    cout<<"Sent "<<bytes_transferred<<endl;
}

main.cpp中没有其他地方可以调用io_service.run。我注意到,如果我打电话     在io_service.run()之后的io_service.reset()它工作正常,每次调用handler。

如果没有io_service.reset()

,我该如何解决这个问题

提前致谢

3 个答案:

答案 0 :(得分:1)

我不理解对调用io_service::reset()的厌恶。在这种情况下,必须在对io_service::run()的任何后续调用之前调用:

  在前一次调用时,必须在reset()run()run_one()poll()函数的任何第二次或更高版本的调用之前调用

poll_one()由于io_service被停止或停止工作而返回这些函数。

由于抛出异常,线程可能会从run()返回,但io_service既没有停止也没有停止工作。在这种情况下,线程可以在不调用run()的情况下调用reset()


当前Client::sendCommand()是同步的。它是一个实现细节,它启动异步操作,然后阻塞io_service::run()等待操作完成。除非在socket上有多个线程调用命令,否则运行io_service的多个线程或写操作需要是可取消的,例如从超时开始,那么它在功能上是等效的并且可能更容易实现Client::sendCommand()具有同步write()

void Client::sendCommand(const string & p_command)
{
  boost::system::error_code ec;
  std::size_t bytes_transferred =
      boost::asio::write(socket, boost::asio::buffer(p_command), ec);
  onSendingFinished(ec, bytes_transferred);
}

如果Client::sendCommand()需要异步,那么:

  • io_service应该从Client::sendCommand()之外运行。如果io_service并不总是有出色的工作,那么run()可以在io_service::run()返回时使用{}。有关p_command阻止和取消阻止的详细信息,请参阅io_service::work答案。
  • 作为缓冲区(Client::onSendingFinished())提供给this的底层内存需要保持有效,直到调用了操作的处理程序p_command为止。在这种情况下,可能需要在Client::sendCommand()中复制{{1}},将副本写入套接字,然后从处理程序中删除副本。

      

    [...]底层内存块的所有权由调用者保留,调用者必须保证它们在调用处理程序之前保持有效。

答案 1 :(得分:1)

虽然偶尔致电reset()并非天生不好,但有两种典型的方法可以避免这样做。

  1. 在第一个处理程序中启动新的异步操作。 run()仅在所有处理程序完成后才返回,因此在处理程序中启动的新异步操作仍然及时阻止io_service

  2. 使用io_service::work。如果您使用io_service::work作为参数创建了io_service的实例,那么只要run()对象保持活动状态,您对work的后续调用就不会返回。因此,您不必重置任何东西。当然,这意味着如果您希望work永远阻止阻止,您的处理程序或其他线程中的任何一个都必须在某个时间销毁run()对象。

答案 2 :(得分:0)

只是发送消息是非常不寻常的,双向通信更为常见。

如果您也实现了接收器,那么您的接收代码将始终需要在io_service中运行接收处理程序,并且您不会遇到此问题...