From 23574ab2ba1c6639f5ae10c207656886aafbddaf Mon Sep 17 00:00:00 2001 From: xfy911 Date: Tue, 9 Jun 2026 03:06:50 +0800 Subject: [PATCH] =?UTF-8?q?feat(proxy):=20=E8=BF=9E=E6=8E=A5=E6=B1=A0?= =?UTF-8?q?=E5=A4=A7=E5=B0=8F=E5=8F=AF=E9=85=8D=E7=BD=AE=EF=BC=88=E9=BB=98?= =?UTF-8?q?=E8=AE=A44=EF=BC=8C=E6=9C=80=E5=A4=A716=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - proxy.h: COCOON_MAX_POOL_SIZE → COCOON_POOL_MAX_CAPACITY(16) + COCOON_POOL_DEFAULT_SIZE(4) - proxy.c: proxy_pool_init 接收 max_pool_size,自动裁剪到上限 - proxy.c: proxy_add_rule 新增 pool_size 参数 - cocoon.h: 配置结构新增 pool_size 字段 - config.c: JSON 解析 pool_size 数字字段,默认值为 4 - server.c: 调用 proxy_add_rule 时传入配置值 - cocoon.json: 示例配置添加 pool_size 展示 编译零警告,142 单元测试 + 90 集成测试全部通过。 --- .cocoon-plan.md | 19 +++++++++++++++---- cocoon.h | 1 + cocoon.json | 4 ++-- config.c | 6 ++++++ proxy.c | 29 ++++++++++++++++++----------- proxy.h | 13 ++++++++----- server.c | 2 +- 7 files changed, 51 insertions(+), 23 deletions(-) diff --git a/.cocoon-plan.md b/.cocoon-plan.md index 0c4a9a6..9b7de00 100644 --- a/.cocoon-plan.md +++ b/.cocoon-plan.md @@ -64,13 +64,24 @@ - 当前仅做编译和测试验证,不添加新代码 ## 待办池(活跃) -1. **HTTP/2 代理支持** — 将反向代理接入 HTTP/2 流(当前仅 HTTP/1.1) -2. 虚拟主机 / 多站点 — 低优先级 -3. 加权轮询 / 主动健康检查 — 负载均衡进阶(当前为被动检测) -4. 连接池最大连接数可配置 — 当前固定为4 +1. ~~连接池最大连接数可配置 — 当前固定为4~~ ✅ 2026-06-09 +2. **HTTP/2 代理支持** — 将反向代理接入 HTTP/2 流(当前仅 HTTP/1.1) +3. 虚拟主机 / 多站点 — 低优先级 +4. 加权轮询 / 主动健康检查 — 负载均衡进阶(当前为被动检测) ## 最近行动记录 +- 2026-06-09 03:00: **连接池大小可配置** + - `proxy.h`: `COCOON_MAX_POOL_SIZE` → `COCOON_POOL_MAX_CAPACITY`(上限16)+ `COCOON_POOL_DEFAULT_SIZE`(默认4),`cocoon_conn_pool_t` 新增 `max_size` 字段 + - `proxy.c`: `proxy_pool_init` 接收 `max_pool_size` 参数,自动裁剪到上限;所有循环改用 `backend->pool.max_size` + - `proxy.c`: `proxy_add_rule` 新增 `pool_size` 参数,传递给 `parse_backend_url` → `proxy_pool_init` + - `cocoon.h`: `proxies` 配置结构新增 `uint32_t pool_size` 字段 + - `config.c`: JSON 解析器新增 `pool_size` 数字字段解析,默认值为 4 + - `server.c`: 调用 `proxy_add_rule` 时传入配置的 `pool_size` + - `cocoon.json`: 示例配置添加 `pool_size` 展示(`/api` → 8,`/backend` → 4) + - 编译零警告,142 单元测试 + 90 集成测试全部通过 + - 提交已推送 `main` + - 2026-06-09 00:15: **后端连接池/keep-alive** - `proxy.h`: 新增 `cocoon_pooled_conn_t` / `cocoon_conn_pool_t`(pthread_mutex 保护),后端嵌入连接池 - `proxy.c`: 实现 `proxy_pool_init`/`destroy`/`acquire`/`release` + `proxy_config_destroy` diff --git a/cocoon.h b/cocoon.h index a9f6572..1421f5d 100644 --- a/cocoon.h +++ b/cocoon.h @@ -56,6 +56,7 @@ typedef struct cocoon_config { struct { char prefix[256]; char target[256]; + uint32_t pool_size; /* 连接池大小(默认4,最大16) */ } proxies[COCOON_MAX_PROXY_RULES]; size_t num_proxies; } cocoon_config_t; diff --git a/cocoon.json b/cocoon.json index 72a9b9f..5564418 100644 --- a/cocoon.json +++ b/cocoon.json @@ -11,8 +11,8 @@ "plugins": ["plugins/hello.so"], "access_log": "-", "proxies": [ - {"prefix": "/api", "target": "http://localhost:3000"}, + {"prefix": "/api", "target": "http://localhost:3000", "pool_size": 8}, {"prefix": "/api", "target": "http://localhost:3001"}, - {"prefix": "/backend", "target": "https://localhost:8443"} + {"prefix": "/backend", "target": "https://localhost:8443", "pool_size": 4} ] } diff --git a/config.c b/config.c index 3f959e8..1eb7822 100644 --- a/config.c +++ b/config.c @@ -436,6 +436,9 @@ bool config_load_from_file(const char *path, cocoon_config_t *config) { } else if (strcmp(pk, "target") == 0 && pval.type == TOKEN_STRING) { char *v = token_str_dup(&pval); if (v) { strncpy(target, v, sizeof(target)-1); free(v); } + } else if (strcmp(pk, "pool_size") == 0 && pval.type == TOKEN_NUMBER) { + char *v = token_str_dup(&pval); + if (v) { config->proxies[config->num_proxies].pool_size = (uint32_t)atoi(v); free(v); } } free(pk); token_t psep = parser_next_token(&p); @@ -454,6 +457,9 @@ bool config_load_from_file(const char *path, cocoon_config_t *config) { if (target_len >= sizeof(config->proxies[0].target)) target_len = sizeof(config->proxies[0].target) - 1; memcpy(config->proxies[config->num_proxies].target, target, target_len); config->proxies[config->num_proxies].target[target_len] = '\0'; + if (config->proxies[config->num_proxies].pool_size == 0) { + config->proxies[config->num_proxies].pool_size = 4; /* 默认连接池大小 */ + } config->num_proxies++; } } else { diff --git a/proxy.c b/proxy.c index 91a5d66..f854480 100644 --- a/proxy.c +++ b/proxy.c @@ -32,10 +32,17 @@ static void backend_init_health(cocoon_proxy_backend_t *backend) { backend->last_check = 0; } -void proxy_pool_init(cocoon_proxy_backend_t *backend) { +void proxy_pool_init(cocoon_proxy_backend_t *backend, size_t max_pool_size) { memset(&backend->pool, 0, sizeof(backend->pool)); + backend->pool.max_size = max_pool_size; + if (backend->pool.max_size > COCOON_POOL_MAX_CAPACITY) { + backend->pool.max_size = COCOON_POOL_MAX_CAPACITY; + } + if (backend->pool.max_size == 0) { + backend->pool.max_size = COCOON_POOL_DEFAULT_SIZE; + } pthread_mutex_init(&backend->pool.mutex, NULL); - for (size_t i = 0; i < COCOON_MAX_POOL_SIZE; i++) { + for (size_t i = 0; i < COCOON_POOL_MAX_CAPACITY; i++) { backend->pool.conns[i].fd = COCOON_INVALID_SOCKET; backend->pool.conns[i].tls_conn = NULL; backend->pool.conns[i].in_use = false; @@ -46,7 +53,7 @@ void proxy_pool_init(cocoon_proxy_backend_t *backend) { void proxy_pool_destroy(cocoon_proxy_backend_t *backend) { if (!backend) return; pthread_mutex_lock(&backend->pool.mutex); - for (size_t i = 0; i < COCOON_MAX_POOL_SIZE; i++) { + for (size_t i = 0; i < backend->pool.max_size; i++) { cocoon_pooled_conn_t *pc = &backend->pool.conns[i]; if (pc->fd != COCOON_INVALID_SOCKET) { cocoon_socket_close(pc->fd); @@ -74,7 +81,7 @@ bool proxy_pool_acquire(cocoon_proxy_backend_t *backend, cocoon_socket_t *pfd, p pthread_mutex_lock(&backend->pool.mutex); /* 1. 查找可用空闲连接(未超时) */ - for (size_t i = 0; i < COCOON_MAX_POOL_SIZE; i++) { + for (size_t i = 0; i < backend->pool.max_size; i++) { cocoon_pooled_conn_t *pc = &backend->pool.conns[i]; if (pc->in_use) continue; if (pc->fd == COCOON_INVALID_SOCKET && !pc->tls_conn) continue; @@ -141,7 +148,7 @@ void proxy_pool_release(cocoon_proxy_backend_t *backend, cocoon_socket_t fd, pro pthread_mutex_lock(&backend->pool.mutex); /* 先尝试找到这个连接的槽位(如果它原本就在池中) */ - for (size_t i = 0; i < COCOON_MAX_POOL_SIZE; i++) { + for (size_t i = 0; i < backend->pool.max_size; i++) { cocoon_pooled_conn_t *pc = &backend->pool.conns[i]; if (pc->in_use && ((use_https && pc->tls_conn == tls_conn) || @@ -155,7 +162,7 @@ void proxy_pool_release(cocoon_proxy_backend_t *backend, cocoon_socket_t fd, pro } /* 如果是新建连接,找一个空槽位放入 */ - for (size_t i = 0; i < COCOON_MAX_POOL_SIZE; i++) { + for (size_t i = 0; i < backend->pool.max_size; i++) { cocoon_pooled_conn_t *pc = &backend->pool.conns[i]; if (pc->fd == COCOON_INVALID_SOCKET && !pc->tls_conn) { pc->fd = fd; @@ -179,7 +186,7 @@ void proxy_pool_release(cocoon_proxy_backend_t *backend, cocoon_socket_t fd, pro } } -static void parse_backend_url(const char *target_url, cocoon_proxy_backend_t *backend) { +static void parse_backend_url(const char *target_url, cocoon_proxy_backend_t *backend, size_t pool_size) { /* 解析目标URL */ bool https = false; const char *url = target_url; @@ -237,10 +244,10 @@ static void parse_backend_url(const char *target_url, cocoon_proxy_backend_t *ba } /* 初始化连接池 */ - proxy_pool_init(backend); + proxy_pool_init(backend, pool_size); } -bool proxy_add_rule(cocoon_proxy_config_t *cfg, const char *prefix, const char *target_url) { +bool proxy_add_rule(cocoon_proxy_config_t *cfg, const char *prefix, const char *target_url, size_t pool_size) { if (!prefix || !target_url || prefix[0] == '\0' || target_url[0] == '\0') { return false; } @@ -261,7 +268,7 @@ bool proxy_add_rule(cocoon_proxy_config_t *cfg, const char *prefix, const char * return false; } cocoon_proxy_backend_t *backend = &rule->backends[rule->backend_count]; - parse_backend_url(target_url, backend); + parse_backend_url(target_url, backend, pool_size); backend_init_health(backend); log_info("追加后端: %s -> %s://%s:%d%s", rule->path_prefix, @@ -286,7 +293,7 @@ bool proxy_add_rule(cocoon_proxy_config_t *cfg, const char *prefix, const char * rule->current_index = 0; cocoon_proxy_backend_t *backend = &rule->backends[rule->backend_count]; - parse_backend_url(target_url, backend); + parse_backend_url(target_url, backend, pool_size); backend_init_health(backend); rule->backend_count++; diff --git a/proxy.h b/proxy.h index fd5d175..56a2014 100644 --- a/proxy.h +++ b/proxy.h @@ -17,7 +17,9 @@ #include #include -#define COCOON_MAX_POOL_SIZE 4 +/* === 连接池可配置 === */ +#define COCOON_POOL_MAX_CAPACITY 16 /**< 连接池最大容量上限 */ +#define COCOON_POOL_DEFAULT_SIZE 4 /**< 默认连接池大小 */ #define COCOON_POOL_IDLE_TIMEOUT_MS 30000 #define COCOON_MAX_PROXY_BACKENDS 8 @@ -38,8 +40,9 @@ typedef struct { * cocoon_conn_pool_t - 连接池 */ typedef struct { - cocoon_pooled_conn_t conns[COCOON_MAX_POOL_SIZE]; /**< 空闲连接数组 */ - pthread_mutex_t mutex; /**< 保护锁 */ + cocoon_pooled_conn_t conns[COCOON_POOL_MAX_CAPACITY]; /**< 空闲连接数组(上限16) */ + size_t max_size; /**< 实际配置大小(默认4) */ + pthread_mutex_t mutex; /**< 保护锁 */ } cocoon_conn_pool_t; /** @@ -90,7 +93,7 @@ void proxy_init(cocoon_proxy_config_t *cfg); * @param target_url 目标URL(如 "http://localhost:3000") * @return true 成功 */ -bool proxy_add_rule(cocoon_proxy_config_t *cfg, const char *prefix, const char *target_url); +bool proxy_add_rule(cocoon_proxy_config_t *cfg, const char *prefix, const char *target_url, size_t pool_size); /** * proxy_match - 查找匹配路径的代理规则 @@ -129,7 +132,7 @@ bool proxy_forward(cocoon_socket_t client_fd, const http_request_t *req, /** * proxy_pool_init - 初始化后端连接池 */ -void proxy_pool_init(cocoon_proxy_backend_t *backend); +void proxy_pool_init(cocoon_proxy_backend_t *backend, size_t max_pool_size); /** * proxy_pool_destroy - 销毁后端连接池,关闭所有连接 diff --git a/server.c b/server.c index 30c5ef2..f238b4e 100644 --- a/server.c +++ b/server.c @@ -1265,7 +1265,7 @@ server_context_t *server_create(const cocoon_config_t *config) { /* 初始化反向代理配置 */ proxy_init(&ctx->proxy_config); for (size_t i = 0; i < ctx->config.num_proxies; i++) { - proxy_add_rule(&ctx->proxy_config, ctx->config.proxies[i].prefix, ctx->config.proxies[i].target); + proxy_add_rule(&ctx->proxy_config, ctx->config.proxies[i].prefix, ctx->config.proxies[i].target, ctx->config.proxies[i].pool_size); } /* 加载插件 */