恒美微站
首页
关于我们
建站服务
主题模板
案例展示
资讯中心
联系我们
Drogon 开源 C++ Web 应用框架深度解析:从协程到高并发实战
首页
资讯中心
/
Drogon 开源 C++ Web 应用框架深度解析:从协程到高并发实战
Drogon 开源 C++ Web 应用框架深度解析:从协程到高并发实战
发布时间:2026/8/30 5:56:04
1. 引言为什么还需要一个 C Web 框架在 PythonDjango/FastAPI、GoGin、JavaSpring Boot几乎垄断 Web 服务端开发的今天用 C 写 Web 服务的理由反而越来越硬极致性能单机吞吐量是脚本语言的数倍到数十倍CPU 密集与高 QPS 场景下优势明显低资源占用内存占用可控适合容器化部署与边缘计算设备与现有 C 技术栈无缝衔接算法库、音视频处理、游戏服务、量化交易等核心逻辑本身就是 C直接用 C 写 HTTP 服务可避免跨语言桥接云原生趋势Serverless / 微服务对冷启动与单实例吞吐有苛刻要求C 天然占优。但 C 写 Web 服务的痛点也很明显标准库没有 HTTP 服务器、没有路由、没有 JSON 与 ORM 的一体化方案需要自己组装 Asio Beast 序列化库 线程池工程成本极高。Drogon 正是为了填平这个鸿沟而生的一体化 Web 应用框架。2. Drogon 简介与开源信息项目信息名称Drogondrogon/drogon取自《权力的游戏》龙名开源协议MIT宽松可商用语言标准C17推荐 C20/23 使用协程核心作者an-taoAn Tao腾讯 Tars 框架核心成员定位跨平台高性能 HTTP/WebSocket 应用框架内置 ORM、过滤器、WebSocket、协程支持支持平台Linux / macOS / Windows / FreeBSD / OpenWrt 等核心依赖可选libuv、OpenSSL、jsoncpp、SQLite3、PostgreSQL、MySQL/MariaDB、Redis 客户端官方仓库https://github.com/drogon/drogon配套工具drogon_ctl命令行脚手架建项目/控制器/过滤器/ORM 模型Drogon 与很多组装型框架不同它把HTTP 服务端、路由分发、参数解析、JSON 序列化、数据库 ORM、WebSocket、协程并发、静态文件、过滤器中间件全部收进一个框架开箱即用。官方 BenchmarkTechEmpower 类测试中长期位于 C Web 框架第一梯队常与 nginx、Go 的 gin 同台竞技。3. 核心特性与使用优点3.1 异步与协程双引擎天然高并发Drogon 的事件循环基于非阻塞 I/O 多路复用Linux epoll / macOS kqueue / Windows IOCP默认线程池模型与 nginx 类似主线程负责 accept 新连接并分发I/O 线程默认与 CPU 核数相关各自持有独立事件循环处理连接读写业务线程可配置数量承接耗时业务避免阻塞 I/O 循环。C20 协程支持是 Drogon 的杀手锏co_await 一个异步数据库查询或 HTTP 请求代码看起来是同步顺序的实际却不占线程。相比回调地狱Beast 的 async 链与每连接一线程传统阻塞模型开发效率与并发能力兼得。// 同步写法背后是协程不阻塞线程却可读性极佳 TaskHttpResponsePtr getUser(const HttpRequestPtr req) { auto dbResult co_await dbClient-execSqlCoro( SELECT name, email FROM users WHERE id $1, req-getParameter(id)); auto resp HttpResponse::newHttpJsonResponse( drogon::json{{name, dbResult[0][name].asstd::string()}}); co_return resp; }3.2 一体化路由、ORM、过滤器开箱即用不需要像Beast 自研路由 自选 JSON 自接数据库那样拼积木。Drogon 内置注解式路由ADD_METHOD_TO 宏 / METHOD_ADD 宏或 C17 的 HTTP_METHOD 注解宏把 URL 路径直接绑到成员函数ORMorm::DbClient链式查询构造器 类型安全的模型类支持 PostgreSQL / MySQL / SQLite3过滤器Filter类似中间件登录校验、权限控制、限流只需注册一个过滤器JSON 支持drogon::json 是 jsoncpp 的轻封装HttpResponse::newHttpJsonResponse 一键返回 JSONWebSocketWebSocketController 接口化握手、收发、广播开箱即用静态文件服务配置 document root 即可托管前端资源无需 nginx 前置。3.3 性能与资源控制零拷贝传输路径响应数据在多数路径下直接走 sendfile / writev 批量发送连接复用HTTP/1.1 keep-alive、HTTP/2需 OpenSSL 支持默认开启精细线程池client_threads_num / threads_num 可独立配置避免业务线程抢占 I/O 线程连接级超时、请求体大小限制、SSL/TLS 终结全部内置无需再套一层网关。3.4 开发效率与工程质量drogon_ctl 脚手架drogon_ctl create project xxx 生成工程骨架drogon_ctl create controller 生成控制器模板配置驱动config.json / config.yaml 声明端口、线程数、日志级别、数据库连接池等无需改代码调优内置日志基于 spdlog 风格、统一异常处理、drogon::app().run() 一键启动。4. 使用场景场景说明为什么选 Drogon高并发 API 网关 / 微服务短请求、高 QPS、低延迟协程 事件循环单机吞吐远超脚本框架游戏后端 / 实时对战服务WebSocket 长连接、广播推送内置 WebSocket 控制器 协程房间逻辑音视频 / 算法服务封装C 算法库对外暴露 HTTP 接口同栈集成避免 Python 桥接开销量化交易 / 高频行情服务毫秒级延迟敏感零拷贝 epoll延迟可预测IoT / 边缘设备 Web 服务资源受限、需静态文件 轻 API无重型依赖可裁剪编译支持 OpenWrt内部管理系统后端CRUD 权限 报表内置 ORM 过滤器开发效率接近脚本框架嵌入式设备管理面板设备本地 Web 配置页单二进制分发静态文件 REST 一体5. 快速上手从零搭一个服务5.1 安装与工程生成推荐方式一vcpkgvcpkg install drogon推荐方式二源码编译可裁剪依赖git clone https://github.com/drogon/drogon cd drogon mkdir build cd build cmake .. -DCMAKE_BUILD_TYPERelease -DBUILD_EXAMPLESOFF cmake --build . -j$(nproc) cmake --install .生成工程骨架drogon_ctl create project hello_drogon cd hello_drogon mkdir build cd build cmake .. cmake --build . ./hello_drogon浏览器访问 http://localhost:8080默认返回框架欢迎页/api/hello 返回 JSON。5.2 最小 CMake 工程FetchContentcmake_minimum_required(VERSION 3.14) project(hello_drogon CXX) set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) include(FetchContent) FetchContent_Declare(drogon GIT_REPOSITORY https://github.com/drogon/drogon GIT_TAG v1.9.6 ) FetchContent_MakeAvailable(drogon) add_executable(hello_drogon main.cpp) target_link_libraries(hello_drogon PRIVATE drogon)5.3 第一个控制器// main.cpp #include drogon/drogon.h int main() { drogon::app() .addListener(0.0.0.0, 8080) .setThreadNum(4) // I/O 线程数 .setClientThreadsNum(4) // 业务线程数 .run(); }// controllers/HelloController.h —— 注解式路由C17 风格 #pragma once #include drogon/HttpController.h class HelloController : public drogon::HttpControllerHelloController { public: METHOD_LIST_BEGIN ADD_METHOD_TO(HelloController::hello, /api/hello, drogon::Get); METHOD_LIST_END void hello(const drogon::HttpRequestPtr req, std::functionvoid(const drogon::HttpResponsePtr) callback) { auto resp drogon::HttpResponse::newHttpJsonResponse( drogon::json{{message, Hello, Drogon!}}); callback(resp); } };ADD_METHOD_TO(类::方法, /路径, HttpMethod) 即完成注册框架自动完成路径匹配、HTTP 方法校验、参数绑定业务代码只关心收到请求→返回响应。6. 具体使用方式详解6.1 路由与参数绑定Drogon 路由支持路径参数{} 占位与查询参数ADD_METHOD_TO(UserController::info, /user/{id}, drogon::Get, UserFilter); void UserController::info(const HttpRequestPtr req, std::functionvoid(const HttpResponsePtr) callback, std::string id) // 第 3 个参数起按路径占位顺序绑定 { // 查询参数: /user/42?fieldsname,email auto fields req-getOptionalParameterstd::string(fields); // 请求体 JSON auto bodyJson req-getJsonObject(); // 响应 auto resp HttpResponse::newHttpResponse(); resp-setStatusCode(k200OK); resp-setBody(user id id); callback(resp); }常用请求 API 一览API作用req-getMethod()HTTP 方法req-getPath() / getFullPath()路径 / 完整路径req-getParameter(k) / getOptionalParameterT(k)查询参数后者带类型转换与空安全req-getJsonObject()解析请求体 JSONjsoncpp 对象req-getHeaders() / getHeader(k)请求头req-getBody()原始请求体req-getCookie(k)Cookiereq-getPeerAddr() / getLocalAddr()对端 / 本端地址6.2 JSON 响应与文件响应// JSON 响应 auto resp HttpResponse::newHttpJsonResponse( drogon::json{{code, 0}, {data, drogon::json::array({1, 2, 3})}}); // 文件响应自动识别 Content-Type大文件走零拷贝 auto fileResp HttpResponse::newFileResponse(/var/www/report.pdf); // 字符串 自定义类型 auto resp2 HttpResponse::newHttpResponse(); resp2-setContentTypeCode(CT_TEXT_HTML); resp2-setBody(h1hello/h1);6.3 过滤器中间件登录与权限控制// filters/LoginFilter.h class LoginFilter : public drogon::HttpFilterLoginFilter { public: void doFilter(const HttpRequestPtr req, FilterCallback fcb, FilterChainCallback fccb) override { auto token req-getHeader(X-Token); if (token valid-token) { fccb(); // 放行继续进入控制器 } else { auto resp HttpResponse::newHttpResponse(); resp-setStatusCode(k401Unauthorized); fcb(resp); // 拦截并直接返回 } } };过滤器支持链式组合ADD_METHOD_TO(..., LoginFilter, AdminFilter) 多个过滤器按声明顺序组成链路适合鉴权、限流、审计日志等横切逻辑。6.4 ORM类型安全的数据库访问auto db drogon::app().getDbClient(); // 1) 链式查询构造器 auto result co_await db-getCoroFuture( Criteria(age, CompareOperator::GT, 18) Criteria(status, CompareOperator::EQ, active), OrderBy(created_at, SortOrder::DESC), Limit(20)); // 2) 原生 SQL 参数绑定防注入 auto res co_await db-execSqlCoro( SELECT id, name FROM users WHERE id $1, 42); for (auto row : res) { auto id row[id].asint64_t(); auto name row[name].asstd::string(); } // 3) 事务 auto trans co_await db-newTransactionCoro(); co_await trans-execSqlCoro(UPDATE accounts SET balance balance - 100 WHERE id $1, 1); co_await trans-execSqlCoro(UPDATE accounts SET balance balance 100 WHERE id $2, 2); co_await trans-commit(); // 或 rollback()ORM 支持模型生成drogon_ctl create model 从数据库表生成 C 模型类字段访问带类型检查编译期即可发现列名错误。6.5 WebSocket实时通信class ChatController : public drogon::WebSocketControllerChatController { public: WS_PATH_LIST_BEGIN WS_PATH_ADD(/ws/chat); WS_PATH_LIST_END void handleNewMessage(const WebSocketConnectionPtr wsConn, std::string message, const WebSocketMessageType type) override { // 广播给所有在线连接 app().getLoop()-queueInLoop([message]() { for (auto conn : app().getWebSocketConnections()) { conn-send(message); } }); } void handleNewConnection(const HttpRequestPtr req, const WebSocketConnectionPtr conn) override { /* 握手成功回调 */ } void handleConnectionClosed(const WebSocketConnectionPtr conn) override { /* 连接关闭回调 */ } };配合协程与 Redis 订阅可以轻松实现聊天室、实时行情推送、协作白板等服务端广播架构。6.6 C20 协程控制器推荐写法启用 -stdc20 后控制器可以直接用协程返回值TaskHttpResponsePtr OrderController::create(const HttpRequestPtr req) { auto body req-getJsonObject(); auto orderId co_await orderService-createOrder(*body); co_return HttpResponse::newHttpJsonResponse( drogon::json{{order_id, orderId}}); }框架自动把 TaskHttpResponsePtr 挂到事件循环上调度协程挂起时不占线程这是 Drogon 高并发下仍保持代码可读性的关键。6.7 静态文件与 HTTPS 配置config.json{ listeners: [ { address: 0.0.0.0, port: 8080, https: false }, { address: 0.0.0.0, port: 8443, https: true, cert: /etc/ssl/server.crt, key: /etc/ssl/server.key } ], document_root: ./static, static_file_headers: { enable: true, headers: [ {name: Cache-Control, value: max-age3600} ] }, threads_num: 8, client_threads_num: 8, db_clients: [ { name: main, rdbms: postgresql, host: 127.0.0.1, port: 5432, dbname: app, user: app, password: secret, connection_number: 10 } ], log: {log_level: info} }6.8 优雅停机与生命周期钩子int main() { drogon::app() .addListener(0.0.0.0, 8080) .registerBeginningAdvice([]() { // 启动前初始化加载配置、预热连接池 }) .registerPreShutdownAdvice([]() { // 停机前停止接收新请求 }) .registerPostShutdownAdvice([]() { // 资源释放 }) .run(); }7. 底层原理窥探7.1 事件循环与线程模型Drogon 的 EventLoop 是对 epoll/kqueue/IOCP 的封装每个 I/O 线程一个 EventLoop。主线程 accept 后按负载均衡把连接分发到各 EventLoop连接上的读写都注册为非阻塞事件回调在所属 EventLoop 线程内执行天然免锁。耗时业务通过 app().getLoop()-queueInLoop() 或业务线程池执行避免阻塞 I/O 循环。7.2 协程调度器Drogon 自研协程drogon::TaskT / drogon::CoroTask支持自定义 Awaitable。核心是协程挂起时把 continuation 注册到当前 EventLoop 的待调度队列I/O 完成事件触发后恢复执行。这意味着协程恢复始终发生在所属线程不需要跨线程切换数据库等待期间线程立即去处理其他请求线程利用率接近 100%相比回调协程栈帧在堆上保存挂起/恢复开销极小微秒级以下。7.3 HTTP 解析与响应路径Drogon 内置高性能 HTTP/1.x 解析器请求头解析避免逐字节拷贝响应发送优先使用 writev 合并头部与 body静态文件走 sendfile 零拷贝。keep-alive 连接复用避免频繁建连HTTP/2 多路复用开启 SSL 后可用进一步降低队头阻塞。8. 性能表现参考TechEmpower Framework BenchmarksRound 21纯 JSON 序列化场景中Drogon 长期位于 C 框架前列典型表现4 核云主机量级指标数值参考纯 JSON 响应吞吐百万级 req/s优化配置单请求延迟 P99亚毫秒级内存占用空闲连接每连接 KB 级说明性能数字随硬件、编译器GCC/Clang、配置差异较大建议以本机 Benchmark 为准。Drogon 仓库自带 drogon_benchmark 与 TechEmpower 测试代码可复现。9. 与同类框架对比框架范式协程ORMWebSocket静态文件适用定位Drogon异步事件循环原生支持内置内置内置一体化高性能 Web 应用CROW异步无无部分无轻量快速原型Oat异步无无支持支持企业级 REST偏重配置cpp-httplib同步/异步无无无支持单文件嵌入式 HTTP 服务Boost.Beast异步回调需配 Asio coro无协议层无协议/底层网络库nginx事件驱动无无反向代理内置反向代理/网关结论需要完整 Web 应用能力路由ORMWebSocket过滤链且追求性能选 Drogon只需要一个嵌入式 HTTP 端点选 cpp-httplib要自己掌控协议细节选 Beast。10. 常见坑点与避坑指南业务线程阻塞 I/O 循环不要在 I/O 线程回调里做重计算应使用 app().getLoop()-queueInLoop 配合业务线程池或协程。协程与线程亲和性co_await 恢复线程与挂起线程一致不要依赖跨线程数据共享跨线程发请求用 getCoroFuture 系列而非直接共享对象。TaskT 生命周期协程返回的 Task 必须被框架接管控制器返回值、app().getLoop()-createTask不要随手丢弃导致悬挂。配置不生效config.json 需放在工作目录或通过 -c 指定改了端口/线程数记得重启进程。HTTPS 证书路径相对路径基于工作目录解析容器部署建议用绝对路径。数据库连接池耗尽connection_number 过小 慢查询会导致池耗尽配合 execSqlCoro 超时与连接数监控。Windows 编译需 vcpkg 安装 OpenSSL、jsoncpp 等依赖或用 -DBUILD_CTLOFF 裁剪工具链减少编译时间。ADD_METHOD_TO 与类外注册路径冲突/user/{id} 与 /user/me按注册顺序匹配静态路径应注册在前。WebSocket 广播遍历遍历 getWebSocketConnections() 时不要在回调内直接修改连接集合用 queueInLoop 延迟执行。日志级别生产环境 log_level 设为 info 以下debug 会显著拖慢高 QPS 路径。11. FAQ 速查表问题答案Drogon 需要 C20 吗不需要C17 可用全部核心功能C20 才能用协程控制器如何部署到生产编译 Release 单二进制 config.json可配 systemd/容器支持 HTTP/2 吗支持需编译时启用 OpenSSL 并配置 HTTPS能做反向代理吗不擅长建议 nginx 前置Drogon 专注应用服务中文乱码怎么办设置 resp-setContentTypeCode(CT_APPLICATION_JSON) 或显式 UTF-8 Content-Type如何做限流过滤器 令牌桶Redis/本地计数器有集群会话吗会话支持 Cookie/Session可对接 Redis 做分布式会话12. 总结Drogon 是目前 C 生态中少有的开箱即用的一体化 Web 应用框架协程编程模型让异步代码回归顺序可读内置 ORM/过滤器/WebSocket 覆盖了 Web 服务 90% 的日常需求MIT 协议与跨平台支持让它适合从边缘设备到云端微服务的全谱系部署。如果团队已经用 C 承载核心业务又希望用最少的胶水代码对外提供 HTTP/WebSocket 能力Drogon 是当前性价比最高的选择。