优雅地取消 boost::asio::async_read
Cancelling boost::asio::async_read gracefully
我有一个 class 看起来像这样:
class MyConnector : public boost::noncopyable, public boost::enable_shared_from_this<MyConnector>
{
public:
typedef MyConnector this_type;
boost::asio::ip::tcp::socket _plainSocket;
boost::shared_ptr<std::vector<uint8_t>> _readBuffer;
// lot of obvious stuff removed....
void readProtocol()
{
_readBuffer = boost::make_shared<std::vector<uint8_t>>(12, 0);
boost::asio::async_read(_plainSocket, boost::asio::buffer(&_readBuffer->at(0), 12),
boost::bind(&this_type::handleReadProtocol, shared_from_this(),
boost::asio::placeholders::bytes_transferred, boost::asio::placeholders::error));
}
void handleReadProtocol(size_t bytesRead,const boost::system::error_code& error)
{
// handling code removed
}
};
此 class 实例通常在等待接收 12 字节协议,然后再尝试读取完整消息。但是,当我尝试取消此读取操作并销毁对象时,它并没有发生。当我调用 _plainSocket.cancel(ec) 时,它不会使用该 ec 调用 handleReadProtocol。套接字断开连接,但未调用处理程序。
boost::system::error_code ec;
_plainSocket.cancel(ec);
并且使用 shared_from_this() 传递的 MyConnector 对象的 shared_ptr 没有被释放。该对象在堆内存中仍然像僵尸一样。如何以减少 MyConnector 对象引用计数的方式取消 async_read(),从而允许对象自行销毁?
两件事:第一,在 handleReadProtocol
中,确保如果出现错误,不会调用 readProtocol
。取消的操作仍会调用处理程序,但会设置错误代码。
其次,asio 建议在完成连接后关闭并关闭套接字。例如:
asio::post([this] {
if (_plainSocket.is_open()) {
asio::error_code ec;
/* For portable behaviour with respect to graceful closure of a connected socket, call
* shutdown() before closing the socket. */
_plainSocket.shutdown(asio::ip::tcp::socket::shutdown_both, ec);
if (ec) {
Log(fmt::format("Socket shutdown error {}.", ec.message()));
ec.clear();
}
_plainSocket.close(ec);
if (ec)
Log(fmt::format("Socket close error {}.", ec.message()));
}
});
我有一个 class 看起来像这样:
class MyConnector : public boost::noncopyable, public boost::enable_shared_from_this<MyConnector>
{
public:
typedef MyConnector this_type;
boost::asio::ip::tcp::socket _plainSocket;
boost::shared_ptr<std::vector<uint8_t>> _readBuffer;
// lot of obvious stuff removed....
void readProtocol()
{
_readBuffer = boost::make_shared<std::vector<uint8_t>>(12, 0);
boost::asio::async_read(_plainSocket, boost::asio::buffer(&_readBuffer->at(0), 12),
boost::bind(&this_type::handleReadProtocol, shared_from_this(),
boost::asio::placeholders::bytes_transferred, boost::asio::placeholders::error));
}
void handleReadProtocol(size_t bytesRead,const boost::system::error_code& error)
{
// handling code removed
}
};
此 class 实例通常在等待接收 12 字节协议,然后再尝试读取完整消息。但是,当我尝试取消此读取操作并销毁对象时,它并没有发生。当我调用 _plainSocket.cancel(ec) 时,它不会使用该 ec 调用 handleReadProtocol。套接字断开连接,但未调用处理程序。
boost::system::error_code ec;
_plainSocket.cancel(ec);
并且使用 shared_from_this() 传递的 MyConnector 对象的 shared_ptr 没有被释放。该对象在堆内存中仍然像僵尸一样。如何以减少 MyConnector 对象引用计数的方式取消 async_read(),从而允许对象自行销毁?
两件事:第一,在 handleReadProtocol
中,确保如果出现错误,不会调用 readProtocol
。取消的操作仍会调用处理程序,但会设置错误代码。
其次,asio 建议在完成连接后关闭并关闭套接字。例如:
asio::post([this] {
if (_plainSocket.is_open()) {
asio::error_code ec;
/* For portable behaviour with respect to graceful closure of a connected socket, call
* shutdown() before closing the socket. */
_plainSocket.shutdown(asio::ip::tcp::socket::shutdown_both, ec);
if (ec) {
Log(fmt::format("Socket shutdown error {}.", ec.message()));
ec.clear();
}
_plainSocket.close(ec);
if (ec)
Log(fmt::format("Socket close error {}.", ec.message()));
}
});