You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用协程时boost::asio超时处理的最佳实践探讨

更简洁的Boost.Asio协程超时实现方案

你这种手动启动定时器协程、手动管理socket和定时器交互的方式确实有点繁琐,Boost.Asio在协程模式下提供了更优雅的超时实现思路——让连接操作和定时器操作竞争完成,谁先结束就优先处理谁,不需要手动维护复杂的协程间交互逻辑。

优化后的实现代码

我们可以用Boost.Asio的experimental::awaitable_operators(Boost 1.78+版本支持,稳定性已经足够生产环境使用)来实现“先完成即返回”的逻辑,代码会紧凑很多:

#define BOOST_ASIO_HAS_CO_AWAIT
#define BOOST_ASIO_HAS_STD_COROUTINE
#include <iostream>
#include <chrono>
#include <thread>
#include <array>
#include <boost/asio/awaitable.hpp>
#include <boost/asio/co_spawn.hpp>
#include <boost/asio/connect.hpp>
#include <boost/asio/io_context.hpp>
#include <boost/asio/ip/address_v4.hpp>
#include <boost/asio/ip/tcp.hpp>
#include <boost/asio/executor_work_guard.hpp>
#include <boost/asio/experimental/awaitable_operators.hpp>

namespace this_coro = boost::asio::this_coro;
using namespace std::chrono_literals;
// 启用awaitable运算符支持,让我们可以用||实现竞争等待
using namespace boost::asio::experimental::awaitable_operators;

boost::asio::awaitable<void> fail_to_connect() {
    auto executor = co_await this_coro::executor;
    boost::asio::ip::tcp::socket socket{executor};
    const auto ep = boost::asio::ip::tcp::endpoint{
        boost::asio::ip::make_address_v4("192.168.1.52"), 80};
    boost::asio::steady_timer timer{executor, 5s};

    std::cout << "Thread ID: " << std::this_thread::get_id() << " Starting connection" << std::endl;

    // 同时等待连接操作和定时器,谁先完成就先返回结果
    auto [connect_result, timer_result] = co_await (
        boost::asio::async_connect(socket, std::array{ep}, boost::asio::use_awaitable) ||
        timer.async_wait(boost::asio::use_awaitable)
    );

    if (timer_result) {
        // 定时器先触发,说明连接超时
        std::cout << "Thread ID: " << std::this_thread::get_id() << " Connection timed out after 5s" << std::endl;
        socket.close(); // 关闭socket终止未完成的连接操作
    } else if (connect_result) {
        // 连接成功(你的场景里不会走到这里,但保留逻辑完整性)
        std::cout << "Thread ID: " << std::this_thread::get_id() << " Connected successfully" << std::endl;
        timer.cancel(); // 取消定时器避免无用触发
        // 这里可以添加后续的连接处理逻辑
        socket.close();
    }
}

int main() {
    auto ctx = boost::asio::io_context{};
    auto guard = boost::asio::make_work_guard(ctx.get_executor());
    
    // 协程异常处理,捕获并输出错误信息
    boost::asio::co_spawn(ctx, fail_to_connect, [](std::exception_ptr e) {
        if (e) {
            try {
                std::rethrow_exception(e);
            } catch (const boost::system::system_error& err) {
                // 可以在这里判断是否是预期的操作取消异常,避免不必要的输出
                if (err.code() != boost::asio::error::operation_aborted) {
                    std::cout << "Exception: " << err.what() << std::endl;
                }
            }
        }
    });
    
    ctx.run();
}

方案优势

  1. 代码更简洁直观:不需要手动启动单独的定时器协程,用||运算符就能直接表达“连接或定时器谁先完成就处理谁”的逻辑,符合协程的异步编程思维。
  2. 自动处理交互逻辑:不需要手动维护socket关闭和定时器取消的时机——超时触发时关闭socket会自动终止连接操作;连接成功时取消定时器避免后续无用的触发。
  3. 线程上下文安全:所有协程操作都在同一个执行器上运行,和你原来的实现一样,不会出现socket的并发访问问题。

运行输出示例

对应你的场景,运行后会得到类似这样的输出:

Thread ID: 140171855615808 Starting connection
Thread ID: 140171855615808 Connection timed out after 5s

(注:我们在异常处理里过滤了operation_aborted错误,这是socket关闭导致连接操作终止的预期异常,不需要额外输出)

内容的提问来源于stack exchange,提问作者cmannett85

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.29 19:32:45