使用std::future搭配asio::async_connect实现连接超时取消的问题
问题分析与解决方案
你的代码核心问题是没有启动asio的io_context事件循环。asio的所有异步操作都依赖io_context的run()/run_one()等方法驱动执行,你只调用了async_connect但没让io_context跑起来,导致异步连接逻辑根本没被执行,std::future自然永远不会就绪。
修正方案一:结合线程运行io_context
发起异步连接后,启动线程运行io_context,超时后通过停止io_context+关闭socket取消连接:
asio::ip::tcp::endpoint endpoint(asio::ip::make_address(peer.address, ec), peer.port); if (ec) { std::cout << ec.message() << std::endl; return false; } asio::io_context context; asio::ip::tcp::socket socket{context}; std::chrono::milliseconds span(100); // 发起异步连接 std::future<void> connect_status = socket.async_connect(endpoint, asio::use_future); // 启动线程运行io_context std::thread io_thread([&context](){ context.run(); }); // 等待future或超时 bool connected = false; if (connect_status.wait_for(span) == std::future_status::ready) { try { connect_status.get(); // 取出连接结果,失败会抛出异常 connected = true; } catch(const std::exception& e) { std::cout << "连接失败: " << e.what() << std::endl; } } // 无论是否成功,停止io_context并等待线程结束 context.stop(); io_thread.join(); // 超时或连接失败时关闭socket if (!connected) { asio::error_code ignore_ec; socket.close(ignore_ec); return false; } // 连接成功,执行后续操作 // ...
修正方案二:使用asio定时器实现超时(更符合asio异步模型)
避免额外线程开销,用asio自带的steady_timer实现异步超时控制,这是asio推荐的异步超时方式:
asio::ip::tcp::endpoint endpoint(asio::ip::make_address(peer.address, ec), peer.port); if (ec) { std::cout << ec.message() << std::endl; return false; } asio::io_context context; asio::ip::tcp::socket socket{context}; asio::steady_timer timer{context, std::chrono::milliseconds(100)}; bool connected = false; asio::error_code connect_ec, timer_ec; // 设置定时器回调:超时则关闭socket timer.async_wait([&](const asio::error_code& ec) { timer_ec = ec; if (!connected) { asio::error_code ignore_ec; socket.close(ignore_ec); } }); // 发起异步连接 socket.async_connect(endpoint, [&](const asio::error_code& ec) { connect_ec = ec; connected = !ec; if (!timer_ec) { timer.cancel(); // 连接成功,取消定时器 } }); // 运行io_context直到所有异步操作完成 context.run(); if (!connected) { if (timer_ec == asio::error::operation_aborted) { // 定时器被取消,说明连接失败是其他原因 std::cout << "连接失败: " << connect_ec.message() << std::endl; } else { // 超时 std::cout << "连接超时" << std::endl; } return false; } // 连接成功,执行后续操作 // ...
关键说明
- 方案一适合习惯
std::future的场景,但需要额外线程;方案二更贴合asio的异步编程范式,无额外线程开销。 - 无论哪种方式,超时后都需要主动关闭socket终止未完成的连接操作,避免资源泄漏。
内容的提问来源于stack exchange,提问作者ILutRf7
相关产品推荐
相关产品推荐

