# gincpp **Repository Path**: judeli/gincpp ## Basic Information - **Project Name**: gincpp - **Description**: No description available - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-08-28 - **Last Updated**: 2026-09-01 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # ginCpp — C++23 原生协程 Web 框架(gin 风格) 一个 **header-only、零第三方依赖、基于 C++23 协程 + epoll** 的高性能 Web 框架。 API 语义对齐 golang/gin:`Engine` / `GET|POST|...` / `Use` / `Group` / `Context` / 中间件洋葱链。 设计哲学与实现细节见 [docs/](docs/)(含 C4 架构图、Mermaid 时序/状态图、六大支柱映射、压测方法论)。 --- ## 特性 - **C++23 原生协程**:`Task` 急切启动 + 嵌套 continuation 链式恢复;无宏、无 Boost.Coroutine。 - **epoll 事件驱动**:单 `timerfd` 小根堆定时器、`eventfd` 跨线程投递、`IoState.claimed` 就绪/超时竞争消解。 - **多线程 N 事件循环**:连接亲和单线程(免锁、缓存友好);loop0 单点 accept + 轮询分发。 - **异步 IO 线性化**:`co_await sock.read_some_timeout(...)` 同步式代码、无阻塞代价、空闲 60s 超时。 - **gin 风格路由**:radix tree,字面量 `>` `:param` `>` `*catchall` 优先级,注册期中间件快照; 注册期冲突检测(参数名冲突 / catchall 后挂子节点 / 重复注册在启动期报错)、 `RedirectTrailingSlash` / `RedirectFixedPath`(301/307)、`HandleMethodNotAllowed`(405)、 `NoRoute` / `NoMethod` 自定义、路径参数 URL 解码、`Routes()` 枚举、静态文件服务。 - **流式 HTTP 解析**:请求行→头→body(Content-Length / chunked),兼容分片与 pipelining。 - **中间件洋葱链**:`co_await c.Next()` 先下游后收尾,`Abort()` 截断;全局 / 分组 / 嵌套分组逐级继承。 - **优雅关闭**:SIGINT/SIGTERM → 停 accept、关监听、回收线程。 - **测试与压测**:63 个单测/集成测试全绿;路由/解析/JSON/全链路四类内建基准(`make test` / `make bench`)+ **wrk 外部 HTTP 压测**(`make bench-wrk`,4 场景 / 千连接压力)。 --- ## 快速开始 ### 环境 Linux 或 WSL2(依赖 `epoll/timerfd/eventfd`),编译器 g++ 13+(`-std=c++23`)。 ```bash make # 编译 example + tests + bench make test # 运行全部测试(27 个断言全绿) make run # 启动示例服务器 :8080(默认 4 线程) make bench-wrk # wrk 外部 HTTP 压测(需先 apt install wrk) ``` ### 手动启动示例 ```bash ./build/gincpp_example [port=8080] [threads=4] curl http://localhost:8080/hello/world # -> hello, world! curl 'http://localhost:8080/query?a=1' # -> a=1 b=none curl -X POST --data 'hi' http://localhost:8080/echo ``` ### 最小应用 ```cpp #include "gincpp/gincpp.hpp" using namespace gincpp; int main() { Engine app; app.Use([](Context& c) -> Task { // 全局中间件 auto t0 = std::chrono::steady_clock::now(); co_await c.Next(); auto ms = std::chrono::duration( std::chrono::steady_clock::now() - t0).count(); printf("%s -> %d (%.2fms)\n", c.request().path.c_str(), c.response().status, ms); }); app.GET("/", [](Context& c) -> Task { c.String(200, "hello from gincpp\n"); co_return; }); app.GET("/hello/:name", [](Context& c) -> Task { c.String(200, "hello, " + c.Param("name") + "!\n"); co_return; }); app.GET("/query", [](Context& c) -> Task { c.String(200, "a=" + c.Query("a") + " b=" + c.QueryDefault("b", "x") + "\n"); co_return; }); app.POST("/echo", [](Context& c) -> Task { c.String(200, c.GetBody()); co_return; }); app.GET("/json", [](Context& c) -> Task { c.JSON(200, json::object({ {"ok", true}, {"now", 8361294} }).dump()); co_return; }); auto api = app.Group("/api"); // 路由分组 api.GET("/ping", [](Context& c) -> Task { c.JSON(200, R"({"pong":true})"); co_return; }); api.GET("/user/:id", [](Context& c) -> Task { c.JSON(200, json::object({ {"id", c.Param("id")} }).dump()); co_return; }); app.Run(8080, 4); // 4 个事件循环线程,阻塞运行 } ``` --- ## API 速查 ### Engine / 路由注册 ```cpp app.Use(middleware...); // 全局中间件(须先于路由注册,gin 语义,支持变长) app.GET/POST/PUT/DELETE/HEAD/OPTIONS/PATCH(path, handlers...); // 变长 handlers app.Any(path, handlers...); // 注册到全部 7 个方法 app.Handle(method, path, handlers...); app.Group("/prefix", mw...); // 返回 RouterGroup(可带组中间件,链式注册) app.NoRoute(handlers...); // 自定义 404 处理器链 app.NoMethod(handlers...); // 自定义 405 处理器链 app.Static("/static", "/path/to/dir"); // 静态目录服务(内置穿越防护) app.StaticFile("/robots.txt", "/path/file"); // 静态单文件服务 app.Routes(); // 枚举已注册路由 (method, path) // gin 行为开关(默认全部开启) app.RedirectTrailingSlash = true; // /user/ <-> /user 301/307 重定向 app.RedirectFixedPath = true; // 大小写 / 连续斜杠路径修正重定向 app.HandleMethodNotAllowed = true; // 方法不匹配返回 405 app.UnescapePathValues = true; // 路径参数百分号解码 app.Run(port, threads); // 阻塞运行;或 app.Start()/Shutdown() 手动管理 ``` ### RouterGroup(分组) ```cpp auto v1 = app.Group("/v1", auth); // 组中间件 auto admin = v1.Group("/admin", audit); // 嵌套分组继承父组中间件 v1.GET("/ping", h); // 自动带前缀 + 全局 + 组中间件链 v1.Static("/static", dir); // 组内静态服务 ``` ### Context ```cpp c.Param("name"); // 路径参数 c.Query("a"); c.QueryDefault("a", "x"); // query(URL 解码) c.GetBody(); // 请求体 c.Set("k", v); c.Get("k"); // 请求级 KV c.String(status, body); c.JSON(status, body); c.Data(status, body, ctype); c.NoContent(); c.Status(status); c.Header(k, v); c.Next(); c.Abort(); // 中间件链控制 ``` ### 协程 IO(server_impl 内部使用,亦可作为 API) ```cpp co_await sock.read_some_timeout(span, timeout_ms); // -> {n, timed_out, error} co_await sock.write_all(span); // 写完整(EAGAIN 挂起) co_await loop.sleep_for(ms); ``` --- ## 目录结构 ``` include/gincpp/ ├── gincpp.hpp # 总入口 ├── core/ # task.hpp / buffer.hpp / event_loop.hpp ├── net/socket.hpp # Socket 异步 IO ├── http/ # request / response / parser ├── json.hpp # JSON 构建 ├── router.hpp # radix tree 路由 ├── context.hpp # Context + 中间件链 ├── engine.hpp # Engine + RouterGroup └── server.hpp / server_impl.hpp # 多线程服务器 example/main.cpp # 示例应用 tests/ # 单元 + 集成测试 bench/benchmark.cpp # 内建微基准(路由/解析/JSON/全链路) bench/wrk_bench.sh # wrk 外部 HTTP 压测(make bench-wrk) docs/ # 设计文档(01~05) ``` --- ## 文档索引 | 文档 | 内容 | |---|---| | [docs/01-architecture.md](docs/01-architecture.md) | 总体架构、C4 图、六大支柱映射、时序 | | [docs/02-coroutine.md](docs/02-coroutine.md) | Task 协程生命周期、异常、GC、帧内存 | | [docs/03-event-loop.md](docs/03-event-loop.md) | epoll、定时器堆、竞争消解、多线程亲和 | | [docs/04-http-router.md](docs/04-http-router.md) | 流式解析、radix tree、中间件洋葱链 | | [docs/05-engineering.md](docs/05-engineering.md) | 构建/测试/压测方法、内核调优、生产化路线 | --- ## 基准参考 **内建微基准**(WSL2 16 核 VM,`./build/gincpp_bench 8 3000 4`): ``` router static match : ~115 ns/op parser GET : ~530 ns/op (~1.3M req/s) router param match : ~270 ns/op parser chunked: ~620 ns/op full-stack (4 loops): ~46 Kreq/s, p50≈0.14ms, p99≈0.49ms (客户端顺序请求模型,非峰值) ``` **wrk 外部压测**(`make bench-wrk`,示例服务器 4 事件循环,多轮取样典型值): ``` GET / -c100 : ~170K req/s, P50≈0.5ms, P99≈1.7ms GET /hello/world -c100 : ~171K req/s, P50≈0.5ms, P99≈1.6ms GET /json -c100 : ~172K req/s, P50≈0.5ms, P99≈1.7ms GET / -c1000: ~136K req/s, P50≈7ms, P99≈12ms (千连接压力) ``` > WSL2 共享宿主机 CPU,同命令多次吞吐可波动 ±50%;完整方法与场景矩阵见 > [docs/05-engineering.md](docs/05-engineering.md) 第 3.5 节。 ## 许可 MIT。