c++20协程本身不提供异步i/o能力,std::coroutine仅为语法糖,无调度器和awaitable socket封装;直接对libcurl阻塞函数co_await会导致线程阻塞,真正可行方案是使用boost.asio+awaitable或libcurl multi模式轮询。

用 std::coroutine + libcurl 做不了真正的异步GET
直接告诉你结论:C++20 标准库不提供网络 I/O 协程支持,std::coroutine 只是语法糖,没有调度器、没有 awaitable 的 socket 封装。硬套 co_await 到 curl_easy_perform 上,结果是阻塞主线程——它根本不是异步函数。
真正可行的路径只有两条:用封装好的协程网络库(如 cpp-httplib 不支持协程;boost::asio + awaitables 是主流),或者自己把 libcurl 置于 multi interface 模式 + 轮询 + 手动挂起恢复。后者复杂且易出错,不推荐初学者尝试。
boost::asio + awaitable 是目前最稳的方案
Boost 1.70+ 提供了完整的协程 HTTP 客户端支持,底层基于非阻塞 socket 和 io_context 调度,awaitable 可自然挂起等待连接/响应。你需要:
- 安装 Boost 1.75+(含
boost::beast) - 链接
-lboost_system -lssl -lcrypto(HTTPS 必需) - 启用 C++20 编译(
-std=c++20)
最小可运行 GET 示例(HTTPS):
#include <boost>
#include <boost>
#include <boost>
#include <boost>
#include <boost>
#include <boost>
namespace asio = boost::asio;
namespace http = boost::beast::http;
asio::awaitable<void> simple_get() {
auto executor = co_await asio::this_coro::executor;
asio::ip::tcp::resolver resolver{executor};
asio::ssl::context ctx{asio::ssl::context::tlsv13_client};
ctx.set_default_verify_paths();
auto stream = std::make_shared<:ssl::stream>>(
asio::make_strand(executor), ctx);
// 解析并连接
auto results = co_await resolver.async_resolve("httpbin.org", "443", asio::use_awaitable);
co_await stream->async_handshake(asio::ssl::stream_base::client, asio::use_awaitable);
// 构造请求
http::request<:string_body> req{http::verb::get, "/get", 11};
req.set(http::field::host, "httpbin.org");
req.set(http::field::user_agent, "Boost.Beast");
// 发送并读响应
http::write(*stream, req, asio::use_awaitable);
boost::beast::flat_buffer buffer;
http::response<:dynamic_body> res;
co_await http::async_read(*stream, buffer, res, asio::use_awaitable);
// 打印状态码和前 100 字节 body
std::cout (100), buffer.size()));
}
</:dynamic_body></:string_body></:ssl::stream></void></boost></boost></boost></boost></boost></boost>
别漏掉 co_spawn 启动和 io_context::run() 驱动
协程不会自动执行,必须显式启动。常见错误是只写 simple_get() 却没调用 co_spawn,或者忘了 io_context.run() —— 这会导致程序立即退出,什么也不做。
正确入口写法:
int main() {
asio::io_context ioc;
asio::co_spawn(ioc, simple_get(), asio::detached); // 或者用 asio::redirect_error(..., ec)
ioc.run(); // 阻塞直到所有任务完成
}
注意点:
-
co_spawn第二个参数必须是awaitable<t></t>,不能是普通函数或 lambda(除非返回 awaitable) -
asio::detached表示不关心完成结果;若需捕获异常,改用asio::redirect_error(..., ec) -
ioc.run()是单线程驱动;多核需配合ioc.run_work_count或多个io_context实例
HTTPS证书验证失败?先关校验再排查
本地调试时,stream->async_handshake 常因证书路径未设或系统 CA 不可用而报 sslv3 alert handshake failure 或 certificate verify failed。临时绕过验证(仅开发用):
ctx.set_verify_mode(asio::ssl::verify_none); // ⚠️ 生产环境严禁
生产环境应:
- 调用
ctx.set_default_verify_paths()(依赖系统 OpenSSL 配置) - 或显式加载 PEM 文件:
ctx.use_certificate_chain_file("ca-bundle.crt") - 确保目标域名在证书 Subject Alternative Name 中(比如用
http://httpbin.org测试 HTTPS 会失败,必须用https://httpbin.org)
最容易被忽略的是:Beast 默认不发送 Connection: close,长连接可能让后续请求复用旧 socket,导致超时或乱序。显式关闭可加:req.set(http::field::connection, "close");
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











