我是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()
,我该如何解决这个问题提前致谢
答案 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()
并非天生不好,但有两种典型的方法可以避免这样做。
在第一个处理程序中启动新的异步操作。 run()
仅在所有处理程序完成后才返回,因此在处理程序中启动的新异步操作仍然及时阻止io_service
。
使用io_service::work
。如果您使用io_service::work
作为参数创建了io_service
的实例,那么只要run()
对象保持活动状态,您对work
的后续调用就不会返回。因此,您不必重置任何东西。当然,这意味着如果您希望work
永远阻止阻止,您的处理程序或其他线程中的任何一个都必须在某个时间销毁run()
对象。
答案 2 :(得分:0)
只是发送消息是非常不寻常的,双向通信更为常见。
如果您也实现了接收器,那么您的接收代码将始终需要在io_service
中运行接收处理程序,并且您不会遇到此问题...