最可靠超时控制是用std::chrono+std::future::wait_for封装异步网络请求;须指定std::launch::async强制异步,统一用milliseconds单位,避免this悬空,并按错误类型精准重试。

超时控制用 std::chrono + std::future::wait_for 最可靠
直接用 select 或 poll 做 socket 超时容易漏掉 DNS 解析、SSL 握手等阶段的阻塞。C++11 之后更稳妥的方式是把网络请求封装成异步任务,用 std::async 启动,再用 std::future::wait_for 统一控制总耗时。
注意:必须用 std::launch::async 强制异步(默认策略可能延迟执行),否则 wait_for 会立刻返回 std::future_status::ready,超时逻辑失效。
std::async(std::launch::async, [&]() { /* 实际请求逻辑 */ })- 超时单位统一用
std::chrono::milliseconds,避免隐式转换误差 - 别在 lambda 里捕获
this后直接调用成员函数——若对象提前析构,future等待时会 crash
重试逻辑要区分错误类型,不是所有失败都该重试
HTTP 500 可以重试,400/401/404 就不该重试;连接拒绝(ECONNREFUSED)可重试,证书错误(SSL_ERROR_SSL)重试也没用。关键是在底层网络调用后,立即检查 errno 或 HTTP 状态码,再决定是否进入下一轮。
建议把重试判定抽成独立函数,比如:
组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。
bool should_retry(int http_code, int sys_errno) {
if (http_code >= 500 && http_code
- 重试间隔推荐用指数退避:
std::this_thread::sleep_for(std::chrono::milliseconds(100 * (1 - 最大重试次数设为 3 次较合理,超过说明服务端真有问题,再试只是浪费资源
- 每次重试前清空 socket、重连,不要复用已失败的连接句柄
构造函数里别做实际请求,避免异常导致对象半初始化
很多新手把 URL、headers 全塞进构造函数,再顺手调一次 send_request() —— 这会让构造失败时对象处于不可用状态,且无法区分是构造参数错还是网络错。
- 构造函数只保存配置:
url_、timeout_ms_、max_retries_等 - 提供显式
send()或execute()成员函数触发请求 - 返回类型建议用
std::optional<response></response>(C++17)或自定义Result<response></response>,明确表达“可能失败” - 若用 libcurl,记得在析构中调用
curl_easy_cleanup,避免句柄泄漏
线程安全只在必要处加锁,别无脑套 std::mutex
这个类通常单次请求单实例,没必要全局锁。真正需要保护的是共享资源,比如内部共用的 curl_global_init 调用、或重试统计计数器。
-
curl_global_init(CURL_GLOBAL_DEFAULT)是进程级,只需在 main() 开头调一次,不用锁 - 如果支持多线程并发请求,每个实例应持有独立的
CURL*handle,不共享 - 只有当提供
get_total_attempts()这类统计接口时,才对计数器变量加std::atomic_int或轻量锁
超时和重试的边界特别容易模糊——比如 DNS 查询花了 2.8 秒,HTTP 请求又卡了 2.5 秒,总超时设 5 秒,但两次耗时是串行叠加的。得确保整个流程从 send() 调用开始计时,而不是分段计时。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!










