断开连接后正确杀死asio steady_timer

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了断开连接后正确杀死asio steady_timer相关的知识,希望对你有一定的参考价值。

我使用独立的asio编写了一个异步SSL套接字实现,并且在服务器重置/关闭连接后很难让它重新连接。我对asio库很新,所以请耐心等待。

由于io_context::run,调用steady_timer的线程即使在断开连接后仍然被阻止。我的close()逻辑负责重置套接字资源,并且还负责尝试终止计时器。这就是我的代码现在的样子:

创建我的异步作业:

timer.async_wait(std::bind(&ssl_socket::heartbeat, this));

在我的close()方法:

timer.expires_at(std::chrono::steady_clock::now());
timer.cancel();

根据boost docscancel()应该:

取消正在等待计时器的任何异步操作。

也许我误解了这个,但我想这也会取消绑定到io_context的异步作业,但事实并非如此。 io_context::run从未被释放并造成僵局。

这是我的计时器处理程序的样子:

void ssl_socket::heartbeat() {
    spdlog::get("console")->trace("heartbeat called");

    if (connected_) {
        write(heartbeat_token);
        spdlog::get("console")->trace("heartbeat sent");
    }

    timer.expires_at(std::chrono::steady_clock::now() + std::chrono::seconds(heartbeat_interval));
    timer.async_wait(std::bind(&ssl_socket::heartbeat, this));

}

我想让处理程序远离必须验证是否应更新其计时器并让close()处理(如果可能)。

答案

您忽略了错误代码。

根据提升文档,cancel()应该:

取消正在等待计时器的任何异步操作。

这有点误导。当您阅读cancel函数的完整描述时,您会看到:

此函数强制完成针对计时器的任何挂起的异步等待操作。将使用boost::asio::error::operation_aborted错误代码调用每个已取消操作的处理程序。

这意味着,您的处理程序将由cancel函数调用,并且由于您的处理程序只是重新设置了到期时间并再次等待,因此循环永远不会结束。您需要检查错误代码,如果已设置,则只需退出循环。

if(error) return;

以上是关于断开连接后正确杀死asio steady_timer的主要内容,如果未能解决你的问题,请参考以下文章

boost::asio 完全断开连接

C++ 提升 asio 多线程

用lambda函数改写std::asio的例子程序

mysql连接的空闲时间超过8小时后 MySQL自动断开该连接解决方案

TCP重传定时器覆盖/杀死TCP keepalive定时器,延迟断开连接发现

使用极光/友盟推送,APP进程杀死后为啥收不到推送