简体   繁体   中英

boost.asio async_write timeout not working when the server is down ungracefully

I refer to the example from boost example: async_tcp_client.cpp . This example shows how to set timeout for aync_read. So I write a test program to test async_write timeout according to this example. The write code is:

bool AsioAsyncTCPClientImpl::send(const uint8_t* data, int32_t length)
{
    if (!m_isConnected || length <= 0) return false;

    m_deadline.expires_after(std::chrono::seconds(5));
    boost::system::error_code ec;
    boost::asio::async_write(m_client, boost::asio::buffer(data, length), 
        std::bind(&AsioAsyncTCPClientImpl::handleWrite, this, std::placeholders::_1, std::placeholders::_2));
    
    return true;
}

the handleWrite code is:

void AsioAsyncTCPClientImpl::handleWrite(const boost::system::error_code& ec, std::size_t len)
{
    if (!m_started) return;

    if (ec == boost::asio::error::eof)
    {
        fireConnectionCallback(ConnectionState::Disconnected);
        return;
    }
    if (ec)
    {
        fireErrorCallback(ec);
        return;
    }

    m_deadline.expires_at(boost::asio::steady_timer::time_point::max());
}

From my test, if I disable the network or pull out the cable of the PC where the server is running, the async_write will always completed as normal, so the timeout set is not working. I am wondering if I miss something, hope some one familiar with this could give me some clue, Thanks for advance!


Update

The async_wait code:

bool AsioAsyncTCPClientImpl::start()
{
    if (m_started) return true;

    connect();

    m_deadline.async_wait(std::bind(&AsioAsyncTCPClientImpl::checkTimeout, this));

    m_started = true;
    m_ioLoopThread = std::thread(&AsioAsyncTCPClientImpl::loopProcess, this);

    return true;
}

void AsioAsyncTCPClientImpl::checkTimeout()
{
    if (!m_started) return;

    if (m_deadline.expiry() <= boost::asio::steady_timer::clock_type::now())
    {
        std::cout << "wait timeout" << std::endl;
        disconnect();
        m_deadline.expires_at(boost::asio::steady_timer::time_point::max());
    }

    m_deadline.async_wait(std::bind(&AsioAsyncTCPClientImpl::checkTimeout, this));
}

And I put the run method of io_context in a thread, I am not sure if this is right way to do it, because I don't want to run io_context.run() in main function.

void AsioAsyncTCPClientImpl::loopProcess()
{
    while(m_started)
    {
        m_context.run();
    }

    std::cout << "loop process exited" << std::endl;
}

You never await the timer.

Something like

m_deadline.async_wait(
      std::bind(&AsioAsyncTCPClientImpl::handleTimer, this, boost::asio::placeholders::errpr));

And then

void AsioAsyncTCPClientImpl::handleTimer(boost::system::error_code ec) {
    if (!ec) {
         std::cout << "Timeout expired" << std::endl;        
         m_client.cancel();
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM