首页 > 解决方案 > 当服务器异常关闭时,boost.asio async_write 超时不起作用

问题描述

我参考了 boost 示例中的示例:async_tcp_client.cpp。此示例显示如何为 aync_read 设置超时。所以我根据这个例子写了一个测试程序来测试async_write超时。编写代码为:

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

handleWrite 代码是:

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

根据我的测试,如果我禁用网络或拔出运行服务器的 PC 的电缆,async_write 将始终正常完成,因此超时设置不起作用。我想知道我是否遗漏了什么,希望熟悉这方面的人能给我一些线索,谢谢提前!


更新

async_wait 代码:

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

我将 io_context 的 run 方法放在一个线程中,我不确定这是否是正确的方法,因为我不想在 main 函数中运行 io_context.run() 。

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

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

标签: c++timeoutboost-asio

解决方案


你永远不会等待计时器。

就像是

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

接着

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

推荐阅读