asyncweb 是一个用 C11 编写的异步 HTTP / HTTPS / WebSocket 库,客户端与服务端全覆盖。 它构建在协程库 libcoro 之上:高层 API 既有 同步风格(自己驱动事件循环,直接返回结果),也有异步风格(在协程里 await)。
- HTTP/1.1 客户端:同步 + 异步,GET / POST / 任意方法
- HTTP/1.1 服务端:handler 回调 + keep-alive,支持明文与 HTTPS
- WebSocket:客户端 + 服务端,明文 ws 与 wss(over TLS)
- 双 TLS 后端:OpenSSL 或 wolfSSL(编译期选)
- 多平台:POSIX / Windows / lwIP(含 FreeRTOS + 裸机 NO_SYS)
- 内存证书:
*_mem变体支持内嵌 DER/PEM 证书,适配无文件系统的嵌入式目标
- CMake ≥ 3.16、C11 编译器
- libcoro:优先
find_package(系统已装),否则自动 FetchContent 源码 - TLS 后端:OpenSSL(
find_package)或 wolfSSL(find_package优先,否则 FetchContent)
构建时通过 cache 变量选后端:
| 变量 | 取值 | 说明 |
|---|---|---|
ASYNCWEB_OS_BACKEND | posix / win / lwip | OS socket 层。lwip 要求 libcoro 也以 LIBCORO_OS_BACKEND=lwip 构建 |
ASYNCWEB_SSL_BACKEND | openssl / wolfssl | TLS 后端 |
ASYNCWEB_STANDALONE | ON / OFF | 是否构建测试(默认 OFF) |
WebSocket 始终可用(用不到时链接期自动剔除,无需编译期开关)。
# POSIX + OpenSSL
cmake -B build -DASYNCWEB_OS_BACKEND=posix -DASYNCWEB_SSL_BACKEND=openssl
cmake --build build# wolfSSL 后端
cmake -B build -DASYNCWEB_OS_BACKEND=posix -DASYNCWEB_SSL_BACKEND=wolfssl
cmake --build buildcmake -B build -DASYNCWEB_OS_BACKEND=posix -DASYNCWEB_SSL_BACKEND=openssl \
-DCMAKE_INSTALL_PREFIX=/your/prefix
cmake --build build --target install下游 CMake:
find_package(asyncwebREQUIRED) # 透传拉入 libcoro + SSL 后端target_link_libraries(your_appPRIVATEasyncweb::asyncweb)注意:若 wolfSSL 是通过 FetchContent 源码内建(系统未装),则该内建静态库不可导出, asyncweb 会跳过 install 并告警。要安装 asyncweb 请用系统 wolfSSL,或用 openssl 后端。
所有 API 用前须调 anet_init(),结束时 anet_cleanup()。注意状态码取值与 C 惯例相反:
typedefenum { ANET_OK=1, ANET_ERR=0 } anet_status_t;
anet_status_tanet_init();
voidanet_cleanup();同步调用自己驱动事件循环、阻塞到完成,调用方无需管 loop。见
examples/http_get.c。
#include<asyncweb/asyncweb.h>anet_init();
anet_sync_http_response_tresp;
if (anet_sync_http_get("http://postman-echo.com/get", &resp) ==ANET_OK) {
printf("Status: %d %s\n", resp.status_code, resp.status_text);
printf("Body:\n%s\n", resp.body);
anet_sync_http_response_free(&resp);
}
anet_cleanup();在协程里发请求、gen_yield_from_task 等它完成,再从 task->future 读结果:
#include<libcoro/libcoro.h>#include<asyncweb/asyncweb.h>task_t*task(fetch) {
gen_dec_vars(
anet_async_http_response_tresponse;
task_t*req;
);
gen_begin(ctx);
gen_var(req) =anet_async_http_get("http://postman-echo.com/get", &gen_var(response));
gen_yield_from_task(gen_var(req));
if (future_result(gen_var(req)->future) != (void*)ANET_ERR) {
printf("Status: %d\n", gen_var(response).status_code);
printf("Body:\n%s\n", gen_var(response).body);
anet_http_response_free(&gen_var(response));
}
loop_stop();
gen_end(NULL);
}
intmain(void) {
anet_init();
loop_run(fetch());
anet_cleanup();
}handler 填充预置默认值的 resp;accept 循环是一个 task,用 loop_run 驱动。见
examples/http_server.c。
staticvoidhandler(constanet_http_server_request_t*req,
anet_http_server_response_t*resp, void*ud) {
staticcharbody[512];
snprintf(body, sizeof(body), "%s %s", req->method, req->path);
resp->status_code=200;
resp->body=body; /* body_len=0 => strlen(body) */
}
anet_init();
anet_http_server_t*srv=anet_http_server_create(8080, handler, NULL); /* port 0 = 临时端口 */loop_run(anet_http_server_run(srv)); /* 服务到 anet_http_server_stop */anet_http_server_destroy(srv);
anet_cleanup();服务端默认绑
127.0.0.1且无鉴权。要暴露到网络请自行加访问控制。
HTTPS 在 create 与 run 之间加 TLS:
anet_http_server_use_tls(srv, "cert.pem", "key.pem"); /* PEM 文件 */anet_http_server_use_tls_mem(srv, cert, cert_len, key, key_len, is_der); /* 内存证书 */anet_status_tanet_init();
voidanet_cleanup();/* 同步: 阻塞到完成 */anet_status_tanet_sync_http_get(constchar*url, anet_sync_http_response_t*resp);
anet_status_tanet_sync_http_post(constchar*url, constchar*content_type,
constchar*body, anet_sync_http_response_t*resp);
anet_status_tanet_sync_http_request(constchar*method, constchar*host, uint16_tport,
intuse_tls, constchar*path, constchar**headers,
constchar*body, anet_sync_http_response_t*resp);
voidanet_sync_http_response_free(anet_sync_http_response_t*resp);
/* 异步: 返回 task, 在协程里 await */task_t*anet_async_http_get(constchar*url, anet_async_http_response_t*resp);
task_t*anet_async_http_post(constchar*url, constchar*content_type,
constchar*body, anet_async_http_response_t*resp);
task_t*anet_async_http_request(anet_async_http_request_t*req);
voidanet_http_response_free(anet_async_http_response_t*resp);响应结构(同步/异步同形):status_code / status_text / headers / headers_len /
body / body_len。
anet_http_server_t*anet_http_server_create(uint16_tport, anet_http_handler_thandler, void*ud);
intanet_http_server_use_tls(anet_http_server_t*s, constchar*cert_path, constchar*key_path);
intanet_http_server_use_tls_mem(anet_http_server_t*s, constunsigned char*cert, intcert_len,
constunsigned char*key, intkey_len, intis_der);
uint16_tanet_http_server_port(anet_http_server_t*s);
task_t*anet_http_server_run(anet_http_server_t*s);
voidanet_http_server_stop(anet_http_server_t*s);
voidanet_http_server_destroy(anet_http_server_t*s);/* 客户端 */task_t*anet_async_ws_connect(constchar*url, anet_async_ws_t**ws);
task_t*anet_async_ws_connect_mem(constchar*url, constunsigned char*ca, intca_len,
intis_der, anet_async_ws_t**ws); /* wss + 内存 CA */anet_status_tanet_sync_ws_connect(constchar*url, anet_sync_ws_t**ws);
/* 服务端: 升级一个已 accept 的 socket */task_t*anet_async_ws_accept(anet_socket_t*sock, anet_async_ws_t**out);
task_t*anet_async_ws_accept_tls(anet_socket_t*sock, constchar*cert_path,
constchar*key_path, anet_async_ws_t**out);
task_t*anet_async_ws_accept_tls_mem(anet_socket_t*sock, constunsigned char*cert, intcert_len,
constunsigned char*key, intkey_len, intis_der,
anet_async_ws_t**out);
/* 收发: anet_async_ws_send/recv/close/get_state/destroy (+ 对应 anet_sync_ 变体) */include/asyncweb/— 公开头(安装)include/asyncweb_internal/— 内部头(不安装)src/— 实现(sock/socket+stream 层,tls/TLS 后端)examples/— 最小示例tests/— 端到端测试
MIT