news 2026/9/13 4:03:58

Drogon 开源 C++ Web 应用框架深度解析:从协程到高并发实战

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Drogon 开源 C++ Web 应用框架深度解析:从协程到高并发实战

1. 引言:为什么还需要一个 C++ Web 框架

在 Python(Django/FastAPI)、Go(Gin)、Java(Spring Boot)几乎垄断 Web 服务端开发的今天,用 C++ 写 Web 服务的理由反而越来越硬:

  • 极致性能:单机吞吐量是脚本语言的数倍到数十倍,CPU 密集与高 QPS 场景下优势明显;
  • 低资源占用:内存占用可控,适合容器化部署与边缘计算设备;
  • 与现有 C++ 技术栈无缝衔接:算法库、音视频处理、游戏服务、量化交易等核心逻辑本身就是 C++,直接用 C++ 写 HTTP 服务可避免跨语言桥接;
  • 云原生趋势:Serverless / 微服务对冷启动与单实例吞吐有苛刻要求,C++ 天然占优。

但 C++ 写 Web 服务的痛点也很明显:标准库没有 HTTP 服务器、没有路由、没有 JSON 与 ORM 的一体化方案,需要自己组装 Asio + Beast + 序列化库 + 线程池,工程成本极高。Drogon 正是为了填平这个鸿沟而生的一体化 Web 应用框架

2. Drogon 简介与开源信息

项目信息
名称Drogon(drogon/drogon,取自《权力的游戏》龙名)
开源协议MIT(宽松,可商用)
语言标准C++17(推荐 C++20/23 使用协程)
核心作者an-tao(An 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、协程并发、静态文件、过滤器(中间件)全部收进一个框架,开箱即用。官方 Benchmark(TechEmpower 类测试)中长期位于 C++ Web 框架第一梯队,常与 nginx、Go 的 gin 同台竞技。

3. 核心特性与使用优点

3.1 异步与协程双引擎,天然高并发

Drogon 的事件循环基于非阻塞 I/O 多路复用(Linux epoll / macOS kqueue / Windows IOCP),默认线程池模型与 nginx 类似:

  • 主线程:负责 accept 新连接并分发;
  • I/O 线程(默认与 CPU 核数相关):各自持有独立事件循环,处理连接读写;
  • 业务线程:可配置数量,承接耗时业务,避免阻塞 I/O 循环。

C++20 协程支持是 Drogon 的杀手锏:co_await 一个异步数据库查询或 HTTP 请求,代码看起来是同步顺序的,实际却不占线程。相比"回调地狱"(Beast 的 async 链)与"每连接一线程"(传统阻塞模型),开发效率与并发能力兼得。

// 同步写法背后是协程:不阻塞线程,却可读性极佳 Task<HttpResponsePtr> 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"].as<std::string>()}}); co_return resp; }

3.2 一体化:路由、ORM、过滤器开箱即用

不需要像"Beast + 自研路由 + 自选 JSON + 自接数据库"那样拼积木。Drogon 内置:

  • 注解式路由:ADD_METHOD_TO 宏 / METHOD_ADD 宏,或 C++17 的 HTTP_METHOD 注解宏,把 URL 路径直接绑到成员函数;
  • ORM(orm::DbClient):链式查询构造器 + 类型安全的模型类,支持 PostgreSQL / MySQL / SQLite3;
  • 过滤器(Filter):类似中间件,登录校验、权限控制、限流只需注册一个过滤器;
  • JSON 支持:drogon::json 是 jsoncpp 的轻封装,HttpResponse::newHttpJsonResponse 一键返回 JSON;
  • WebSocket:WebSocketController 接口化,握手、收发、广播开箱即用;
  • 静态文件服务:配置 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 安装与工程生成

推荐方式一(vcpkg):

vcpkg install drogon

推荐方式二(源码编译,可裁剪依赖):

git clone https://github.com/drogon/drogon cd drogon mkdir build && cd build cmake .. -DCMAKE_BUILD_TYPE=Release -DBUILD_EXAMPLES=OFF 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 工程(FetchContent)

cmake_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 —— 注解式路由(C++17 风格) #pragma once #include <drogon/HttpController.h> class HelloController : public drogon::HttpController<HelloController> { public: METHOD_LIST_BEGIN ADD_METHOD_TO(HelloController::hello, "/api/hello", drogon::Get); METHOD_LIST_END void hello(const drogon::HttpRequestPtr& req, std::function<void(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::function<void(const HttpResponsePtr&)>&& callback, std::string id) // 第 3 个参数起按路径占位顺序绑定 { // 查询参数: /user/42?fields=name,email auto fields = req->getOptionalParameter<std::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") / getOptionalParameter<T>("k")查询参数(后者带类型转换与空安全)
req->getJsonObject()解析请求体 JSON(jsoncpp 对象)
req->getHeaders() / getHeader("k")请求头
req->getBody()原始请求体
req->getCookie("k")Cookie
req->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("<h1>hello</h1>");

6.3 过滤器(中间件):登录与权限控制

// filters/LoginFilter.h class LoginFilter : public drogon::HttpFilter<LoginFilter> { 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"].as<int64_t>(); auto name = row["name"].as<std::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::WebSocketController<ChatController> { 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 C++20 协程控制器(推荐写法)

启用 -std=c++20 后,控制器可以直接用协程返回值:

Task<HttpResponsePtr> 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}}); }

框架自动把 Task<HttpResponsePtr> 挂到事件循环上调度,协程挂起时不占线程;这是 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-age=3600"} ] }, "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::Task<T> / 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 Benchmarks(Round 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 应用能力(路由+ORM+WebSocket+过滤链)且追求性能,选 Drogon;只需要一个嵌入式 HTTP 端点,选 cpp-httplib;要自己掌控协议细节,选 Beast

10. 常见坑点与避坑指南

  1. 业务线程阻塞 I/O 循环:不要在 I/O 线程回调里做重计算,应使用 app().getLoop()->queueInLoop 配合业务线程池或协程。
  2. 协程与线程亲和性:co_await 恢复线程与挂起线程一致,不要依赖跨线程数据共享;跨线程发请求用 getCoroFuture 系列而非直接共享对象。
  3. Task<T> 生命周期:协程返回的 Task 必须被框架接管(控制器返回值、app().getLoop()->createTask),不要随手丢弃导致悬挂。
  4. 配置不生效:config.json 需放在工作目录或通过 -c 指定;改了端口/线程数记得重启进程。
  5. HTTPS 证书路径:相对路径基于工作目录解析,容器部署建议用绝对路径。
  6. 数据库连接池耗尽:connection_number 过小 + 慢查询会导致池耗尽,配合 execSqlCoro 超时与连接数监控。
  7. Windows 编译:需 vcpkg 安装 OpenSSL、jsoncpp 等依赖,或用 -DBUILD_CTL=OFF 裁剪工具链减少编译时间。
  8. ADD_METHOD_TO 与类外注册:路径冲突(/user/{id} 与 /user/me)按注册顺序匹配,静态路径应注册在前。
  9. WebSocket 广播遍历:遍历 getWebSocketConnections() 时不要在回调内直接修改连接集合,用 queueInLoop 延迟执行。
  10. 日志级别:生产环境 log_level 设为 info 以下,debug 会显著拖慢高 QPS 路径。

11. FAQ 速查表

问题答案
Drogon 需要 C++20 吗?不需要,C++17 可用全部核心功能;C++20 才能用协程控制器
如何部署到生产?编译 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 是当前性价比最高的选择。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/4 20:00:53

从零搭建AI内容治理服务:深度伪造检测与批量审核实战

"AI Threatens Our Economy and Democracy Itself"&#xff0c;这句话自带流量&#xff0c;但放到工程技术人员的桌面上&#xff0c;它不是一个哲学命题&#xff0c;而是一组可以被拆解、被检测、被管控的风险场景。AI 生成内容已经从实验室走向流水线&#xff1a;一…

作者头像 李华
网站建设 2026/9/2 1:06:58

ChatGPT桌面端Codex集成故障排查:从CLI安装到config.toml修复完整指南

ChatGPT 桌面端集成 Codex 后&#xff0c;用户的日常使用从“AI 只能给代码”变成了“AI 可以打开终端、执行命令、修改文件”。这部分新功能的核心依赖不是聊天窗口本身&#xff0c;而是 Codex CLI。大量用户在实际体验时却发现&#xff0c;新的客户端首屏就出现ChatGPT faile…

作者头像 李华
网站建设 2026/9/4 13:23:15

智能驾驶研发工程师笔试全解析:从编程算法到感知规划

2018年那会儿&#xff0c;智能驾驶这四个字在出行行业里几乎就是“高薪”和“技术壁垒”的代名词。滴滴那年的校园招聘内推里&#xff0c;智能驾驶研发工程师这个岗位的笔试&#xff0c;绝对是不少想进自动驾驶圈子同学的第一个硬门槛。我当时身边有不少朋友投了这个岗位&#…

作者头像 李华
网站建设 2026/9/10 3:04:10

大模型应用开发Demo

目录 一.初步连接模型 二.非流式输出的响应结构 三.流式输出的请求体响应结构 四.使用大模型进行情感分析 五.使用大模型进行图像识别 六.使用大模型进行图像生成 七.函数功能的使用 一.初步连接模型 首先&#xff0c;本文采用uv在根目录下创建虚拟环境&#xff0c;代码…

作者头像 李华
网站建设 2026/9/12 15:12:23

AI应用安全加固:从API网关到日志审计的工程实践

这次我们来看一个并不新但必须落到工程里的话题&#xff1a;OpenAI、Anthropic、Google 等百余家公司的联名呼吁&#xff0c;核心不是“AI 会不会攻击人”&#xff0c;而是“恶意 AI 网络攻击已经变成常规威胁&#xff0c;防御必须提前做”。对开发者来说&#xff0c;这条消息对…

作者头像 李华
网站建设 2026/9/2 5:07:46

软考 系统架构设计师历年真题集萃(330)—— 2026年5月系统架构设计师真题23

接前一篇文章:软考 系统架构设计师历年真题集萃(329)—— 2026年5月系统架构设计师真题22 本文内容参考: 嵌入式软件开发中的表驱动法:原理、应用与实战-CSDN博客 特此致谢! 第660题 嵌入式系统强实时性设计通常采用( )。 A. 表驱动、越界检查 B. 静/动态结合、越…

作者头像 李华