- 人工智能
- AI Agent
- 多模态
- 语音
- AI 应用
【免费下载链接】ten-framework
Open-source framework for conversational voice AI agents
导读
minimal-http-server是 libwebsockets(lws)官方示例集中最简的 HTTP 服务器实现:仅用一个 C 源文件,即可把本地目录以静态站点形式发布到http://localhost:7681,并附带自定义 404 错误页、HTTP 安全响应头等能力。本文以该示例为核心,先带你完成构建、运行与验证,再逐字段剖析lws_http_mount与lws_context_creation_info的配置含义,最后结合 TEN-framework 仓库中的实际集成方式(BUILD.gn 与 simple_http_server_cpp),说明如何把这个"最小骨架"扩展成嵌入 TEN 扩展系统中的真实 HTTP 服务。读完你将掌握 lws 静态文件服务的完整配置模型,以及它在 TEN 框架中的落地路径。
一、示例概览:它解决了什么问题
libwebsockets 官方按功能把 HTTP 服务端示例拆成了 20 余个变体(示例总览),其中minimal-http-server被定位为:
Serves a directory over http/1, custom 404 handler
也就是说,它是整个 HTTP 示例家族的最小公共基座:http/1 目录静态服务 + 自定义 404 处理器。其他示例(TLS、Basic Auth、CGI、Server Side Events、多 vhost、SMP 多线程等)都从这一基线向外扩展。
示例完整目录结构如下(源码目录):
minimal-http-server/ ├── CMakeLists.txt # 构建脚本 ├── minimal-http-server.c # 唯一一个 C 源文件 ├── README.md # 官方使用说明 └── mount-origin/ # 静态站点根目录(默认挂载来源) ├── 404.html ├── favicon.ico ├── index.html ├── libwebsockets.org-logo.svg └── strict-csp.svg整个服务端逻辑压缩在 minimal-http-server.c 一个文件里,核心只有三步:定义挂载(mount)→ 创建上下文(context)→ 进入服务循环(service loop)。下面按官方 README 的流程逐步操作。
二、构建:从源码到可执行文件
官方 README 给出的构建命令非常简洁:
cmake . && make这条命令成立的前提与细节,藏在 CMakeLists.txt 中:
project(lws-minimal-http-server C) cmake_minimum_required(VERSION 2.8.12) find_package(libwebsockets CONFIG REQUIRED)find_package(libwebsockets CONFIG REQUIRED):要求系统中已通过cmake --install安装 libwebsockets 的 CMake 配置文件,即先要有一份可用的 lws 开发环境;include(LwsCheckRequirements)后通过require_lws_config(LWS_ROLE_H1 1 requirements)与require_lws_config(LWS_WITH_SERVER 1 requirements)检查当前 lws 构建是否启用了HTTP/1 角色和服务端能力——这两项正是运行本例的最低编译期要求;- 链接阶段优先使用共享库
websockets_shared,否则回退到静态库websockets,并自动带入 lws 的依赖库(LIBWEBSOCKETS_DEP_LIBS)。
构建成功后,工作目录下会生成可执行文件lws-minimal-http-server。
提示:在本仓库中,TEN-framework 通过 BUILD.gn 的
cmake_project("websockets")以 GN 构建系统集成 libwebsockets,同样强制启用了LWS_ROLE_H1=ON与LWS_WITH_SERVER=ON(并额外开启LWS_WITH_NETWORK、LWS_WITH_SSL、LWS_WITH_MBEDTLS)。这意味着在 TEN 的完整构建流程里,上面这两个编译期条件天然满足。
三、运行与验证
官方 README 给出的运行方式为:
./lws-minimal-http-server正常启动时控制台输出类似:
[2018/03/04 09:30:02:7986] USER: LWS minimal http server | visit http://localhost:7681 [2018/03/04 09:30:02:7986] NOTICE: Creating Vhost 'default' port 7681, 1 protocols, IPv6 on随后在浏览器访问http://localhost:7681,即可看到 mount-origin/index.html 渲染出的页面。该页面本身还内置了一个可验证 404 机制的入口:点击其中的notextant.html链接访问一个不存在的页面,服务端会返回自定义的 404.html("404 / Sorry, that file doesn't exist."),而不是浏览器默认错误页。
日志中值得注意的两条信息:
visit http://localhost:7681:由源码中的lwsl_user("LWS minimal http server | visit http://localhost:7681\n")打印,其中lwsl_user对应LLL_USER日志级别;Creating Vhost 'default' port 7681, 1 protocols, IPv6 on:说明 lws 自动创建了名为default的 vhost,绑定 7681 端口,默认同时监听 IPv4/IPv6。
四、核心源码剖析:一个最小 HTTP 服务器的全部配置
4.1 静态目录挂载:lws_http_mount结构体
服务"哪个 URL 映射到哪个本地目录"由 minimal-http-server.c 中的lws_http_mount静态实例描述:
static const struct lws_http_mount mount = { /* .mount_next */ NULL, /* linked-list "next" */ /* .mountpoint */ "/", /* mountpoint URL */ /* .origin */ "./mount-origin", /* serve from dir */ /* .def */ "index.html", /* default filename */ /* .protocol */ NULL, /* .cgienv */ NULL, /* .extra_mimetypes */ NULL, /* .interpret */ NULL, /* .cgi_timeout */ 0, /* .cache_max_age */ 0, /* .auth_mask */ 0, /* .cache_reusable */ 0, /* .cache_revalidate */ 0, /* .cache_intermediaries */ 0, /* .origin_protocol */ LWSMPRO_FILE, /* files in a dir */ /* .mountpoint_len */ 1, /* char count */ /* .basic_auth_login_file */ NULL, };各字段的实践含义:
| 字段 | 值 | 说明 |
|---|---|---|
mount_next | NULL | 挂载点链表指针,本例只有一个挂载;多目录服务时可在此串联 |
mountpoint | "/" | URL 挂载点,根路径/映射到本地目录 |
mountpoint_len | 1 | mountpoint的字符长度,必须与字符串一致("/"为 1 个字符) |
origin | "./mount-origin" | 静态资源来源目录,相对于进程启动时的工作目录,这是最容易踩的坑 |
def | "index.html" | 请求目录时默认返回的文件名 |
origin_protocol | LWSMPRO_FILE | 来源类型为"文件系统目录",即纯静态文件服务(不涉及 CGI) |
basic_auth_login_file | NULL | 未启用 Basic Auth(对应示例见minimal-http-server-basicauth) |
其余为0/NULL的字段(cache_max_age、cache_reusable、cache_revalidate、cache_intermediaries)表示不做 HTTP 缓存控制,可保持默认关闭。
4.2 上下文创建:lws_context_creation_info
服务实例本身由 main 函数 组装:
memset(&info, 0, sizeof info); /* otherwise uninitialized garbage */ info.port = 7681; info.mounts = &mount; info.error_document_404 = "/404.html"; info.options = LWS_SERVER_OPTION_HTTP_HEADERS_SECURITY_BEST_PRACTICES_ENFORCE; if (lws_cmdline_option(argc, argv, "--h2-prior-knowledge")) info.options |= LWS_SERVER_OPTION_H2_PRIOR_KNOWLEDGE; context = lws_create_context(&info);info.port = 7681:监听端口。注意源码注释与官方日志一致——修改监听端口只需改这一个字段;info.mounts = &mount:把上一节的挂载表挂到上下文上;info.error_document_404 = "/404.html":自定义 404 处理器,这正是示例定位中"custom 404 handler"的实现点。请求不存在的路径时,lws 直接返回挂载目录下的404.html(见 mount-origin/404.html);info.options = LWS_SERVER_OPTION_HTTP_HEADERS_SECURITY_BEST_PRACTICES_ENFORCE:启用 lws 内置的 HTTP 安全响应头最佳实践(如 CSP 相关头),这也是为什么首页会展示strict-csp.svg图标;- 若命令行带
--h2-prior-knowledge,再叠加LWS_SERVER_OPTION_H2_PRIOR_KNOWLEDGE,服务将以 HTTP/2 直连方式(h2 prior knowledge,不经 Upgrade 协商)工作。
4.3 服务生命周期:create → service → destroy
context = lws_create_context(&info); ... while (n >= 0 && !interrupted) n = lws_service(context, 0); lws_context_destroy(context);这是 lws 服务端的标准三阶段模型:
lws_create_context(&info):依据info一次性创建上下文与默认 vhost,失败时返回NULL,示例随即以退出码 1 终止;lws_service(context, 0):事件循环核心。第二个参数0表示最多等待 0 秒,即非阻塞轮询;返回值n < 0表示出现致命错误需退出;lws_context_destroy(context):退出循环后统一销毁上下文,释放所有挂载、vhost 与连接资源。
优雅退出由signal(SIGINT, sigint_handler)配合静态标志interrupted实现:收到 Ctrl+C 时置位标志,主循环自然结束,从而保证走完整的销毁路径而不是被信号粗暴打断。
4.4 命令行参数与日志级别
示例内置了一个-d参数用于控制日志级别:
if ((p = lws_cmdline_option(argc, argv, "-d"))) logs = atoi(p); lws_set_log_level(logs, NULL);默认级别为LLL_USER | LLL_ERR | LLL_WARN | LLL_NOTICE。源码注释特别说明:若要看到LLL_INFO及以上更详细的日志,lws 必须以-DCMAKE_BUILD_TYPE=DEBUG构建,RELEASE 构建会裁剪掉这些级别的日志输出。
五、从最小骨架到 TEN 框架:仓库内的真实集成路径
minimal-http-server不止是独立示例——它在当前仓库中有两条可验证的落地线索,能帮助你理解"最小静态服务"如何在真实工程中升级为"可编程 HTTP 服务"。
5.1 构建层面:GN 工程中的 lws 集成
TEN-framework 并未直接编译这个示例,而是以 GN 的cmake_project("websockets")把整个 libwebsockets 作为三方依赖引入(third_party/libwebsockets/BUILD.gn)。其中与本示例直接相关的配置包括:
LWS_ROLE_H1=ON、LWS_WITH_SERVER=ON:与本例 CMakeLists.txt 中的require_lws_config检查项完全对应;LWS_WITH_HTTP2=OFF:当前 TEN 的 lws 协议实现尚未适配 HTTP/2 分帧,故显式关闭(源码注释指出 HTTP/2 要求请求头与请求体分帧发送,与现有 http/1.1 同帧发送不兼容)——因此示例中的--h2-prior-knowledge选项在 TEN 的构建配置下不可用,这属于集成层面的前置限制;LWS_WITH_MBEDTLS=ON、LWS_WITH_SSL=ON:TLS 后端选用 mbedTLS,这也是构建时同步编译 third_party/mbedtls 的原因。
5.2 运行时层面:simple_http_server_cpp 扩展
仓库的示例扩展 simple_http_server_cpp 在 TEN 框架内用同样的 lws API 实现了完整 HTTP 服务,与minimal-http-server形成鲜明的"静态 vs 动态"对照:
- 相同的骨架:
lws_create_context(&info)→while (n >= 0) n = lws_service(ctx, 0)→lws_context_destroy,并且把服务循环搬进了独立线程(create_http_server_thread); - 从静态挂载升级为协议回调:不再依赖
lws_http_mount的文件服务,而是注册lws_protocols回调,在LWS_CALLBACK_HTTP、LWS_CALLBACK_HTTP_BODY、LWS_CALLBACK_HTTP_BODY_COMPLETION、LWS_CALLBACK_HTTP_WRITEABLE等事件中自行解析 GET/POST/PUT/DELETE 等请求(parse_http_method),把 HTTP 请求转换为 TEN 命令(ten_env.send_cmd)下发到 TEN graph; - 关键的 API 补充:
lws_add_http_common_headers+lws_finalize_http_header+lws_write手动拼装响应头与响应体(对应 main.cc),lws_cancel_service用于跨线程唤醒事件循环,lws_callback_on_writable用于按需触发写事件。
对比可见:minimal-http-server展示的是 lws "零回调、纯配置" 的静态服务路径;而 TEN 的simple_http_server_cpp展示的是同一底层 API 面向业务定制的完整形态。二者共用同一套 context/service/destroy 生命周期模型,读懂前者是快速进入后者的最短路径。
六、动手定制:三个高频改动点
基于上文源码,以下改动都是"改一行即可生效"的实操级定制:
- 换端口:修改
info.port = 7681;为其他值(如8000),访问地址随之变化; - 换站点目录:把
mount.origin从"./mount-origin"改为自己的目录(如"./www"),并保证mountpoint_len、mountpoint与def保持一致;注意origin是相对启动目录解析的,建议使用绝对路径避免歧义; - 换 404 页面:修改
info.error_document_404指向的路径,例如"/404.html"改为自定义的"/not-found.html",并在mount-origin下放置对应文件。
若要验证改动,重新执行cmake . && make后再次运行即可,日志中port 7681一行会同步反映新端口。
结语
minimal-http-server用不足百行 C 代码,把 libwebsockets 服务端的三大核心概念——挂载表(lws_http_mount)、上下文信息(lws_context_creation_info)与生命周期循环(create/service/destroy)——完整呈现出来,并顺带演示了自定义 404、安全响应头与可选 HTTP/2 直连。在当前仓库中,它既是 libwebsockets 示例家族的最小基线,也是理解 TEN-framework 如何把该库编译进工程(BUILD.gn)并在扩展内二次开发(simple_http_server_cpp)的入口。建议按本文第二节完成一次构建运行,再对照第四节源码逐字段推敲,即可牢固掌握 lws 静态 HTTP 服务的完整配置模型。
- 人工智能
- AI Agent
- 多模态
- 语音
- AI 应用
【免费下载链接】ten-framework
Open-source framework for conversational voice AI agents
相关推荐
基于 libwebsockets 的最小化 HTTPS 服务器:minimal-http-server-tls 实战与源码解析
基于 libwebsockets 的最小化 HTTPS 服务器:minimal http server tls 实战与源码解析 本指南以 TEN framewo
人工智能AI Agent多模态语音AI 应用Karpenter EC2NodeClass 完全指南:在 AWS 上配置节点类(NodeClass)的每一处细节
Karpenter EC2NodeClass 完全指南:在 AWS 上配置节点类(NodeClass)的每一处细节 导读 本文基于 karpenter prov
人工智能AI Agent多模态语音AI 应用MCP Python SDK 服务端工具(Tools)开发指南:用 `@mcp.tool()` 把普通 Python 函数变成模型可调用的工具
MCP Python SDK 服务端工具(Tools)开发指南:用 @mcp.tool 把普通 Python 函数变成模型可调用的工具 本指南基于 python
人工智能AI Agent多模态语音AI 应用
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考