正常取消boost :: asio :: async_read

时间:2020-03-29 15:33:43

标签: c++ boost-asio asyncsocket

我有一个看起来像这样的课:

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
    }
};

此类实例通常在尝试读取完整消息之前正在等待接收12个字节的协议。但是,当我尝试取消此读取操作并销毁对象时,不会发生。当我调用_plainSocket.cancel(ec)时,它不使用该ec调用handleReadProtocol。套接字断开连接,但未调用处理程序。

boost::system::error_code ec;
_plainSocket.cancel(ec);

并且不释放使用shared_from_this()传递的MyConnector对象的shared_ptr。该对象在堆内存中仍然像僵尸一样。如何以减少MyConnector对象引用计数的方式取消async_read(),从而允许对象自行销毁?

1 个答案:

答案 0 :(得分:0)

两件事情:一,在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()));
     }
  });