)
人工智能AI Agent多模态语音AI 应用【免费下载链接】ten-frameworkOpen-source framework for conversational voice AI agents项目地址https://gitcode.com/TEN-framework/ten-framework点击查看免费下载导读本文以 libwebsocketslws官方示例minimal-http-server-eventlib-smp为主线深入讲解如何构建一个可自由切换事件库libuv / libevent / libev且支持多线程服务SMP的最小 HTTP 服务器。示例源码位于 third_party/libwebsockets/minimal-examples/http-server/minimal-http-server-eventlib-smp/读者读完本文后将掌握-d / -t / --uv / --event / --ev等命令行选项的完整含义、LWS_MAX_SMP 1的编译前提、多线程服务per-thread service的实现原理以及如何通过lws_service_tsi()让多个工作线程并行驱动 lws 事件循环。注意lws 官方在该示例 README 中明确标注 “WARNING: this is under development, its not stable.”即该示例仍处于开发阶段、行为尚未稳定生产环境使用前需自行评估。一、示例定位一个可插拔事件库的多线程 HTTP 服务器minimal-http-server-eventlib-smp是 lws 官方minimal-examples系列中的一员与普通minimal-http-server相比它的核心特点是事件循环后端可切换可通过命令行参数在 libuv、libevent、libev 三种外部事件库之间选择不指定时则回落到 lws 默认的poll()实现支持多线程服务SMP将 lws context 划分为多个 service thread每个线程独立驱动事件循环从而利用多核 CPU 提升并发处理能力。该示例会从启动目录下的./mount-origin子目录对外提供静态文件服务默认首页为index.html并内置 404 错误页处理。相关文件结构如下third_party/libwebsockets/minimal-examples/http-server/minimal-http-server-eventlib-smp/ ├── CMakeLists.txt # 构建脚本 ├── minimal-http-server-eventlib-smp.c # 示例主程序 ├── localhost-100y.cert # TLS 证书配合 -s 选项使用 ├── localhost-100y.key # TLS 私钥 └── mount-origin/ # 静态文件挂载目录 ├── 404.html ├── index.html ├── favicon.ico ├── libwebsockets.org-logo.svg └── strict-csp.svg二、命令行选项完整说明原文档给出了如下选项表本文结合 minimal-http-server-eventlib-smp.c 源码逐一扩充命令行选项含义源码中的对应实现-d loglevel调试日志级别十进制数字例如-d15lws_cmdline_option(argc, argv, -d)读取后调用lws_set_log_level(logs, NULL)设置日志级别-t threads使用的服务线程数量设置info.count_threads若threads 1或threads LWS_MAX_SMP则直接返回 1 退出--uv使用 libuv 事件库lws 必须以-DLWS_WITH_LIBUV1配置编译info.options \| LWS_SERVER_OPTION_LIBUV--event使用 libevent 事件库lws 必须以-DLWS_WITH_LIBEVENT1配置编译info.options \| LWS_SERVER_OPTION_LIBEVENT--ev使用 libev 事件库lws 必须以-DLWS_WITH_LIBEV1配置编译info.options \| LWS_SERVER_OPTION_LIBEV1. 日志级别-d源码中默认日志级别为LLL_USER \| LLL_ERR \| LLL_WARN \| LLL_NOTICE。注释特别提醒要启用高于 NOTICE 级别的日志如LLL_INFO、LLL_PARSER、LLL_HEADER、LLL_EXT、LLL_CLIENT、LLL_LATENCY、LLL_DEBUGlws 必须以-DCMAKE_BUILD_TYPEDEBUG而非RELEASE配置并构建否则这些级别的日志不会被编入库中。示例中这些级别默认被注释掉可按需取消注释。2. 线程数-t与LWS_MAX_SMP上限if ((p lws_cmdline_option(argc, argv, -t))) { info.count_threads (unsigned int)atoi(p); if (info.count_threads 1 || info.count_threads LWS_MAX_SMP) return 1; } else info.count_threads COUNT_THREADS;未指定-t时默认线程数为源码中定义的COUNT_THREADS值为 8指定时取值必须落在[1, LWS_MAX_SMP]区间否则程序直接退出因此要使用多线程libwebsockets 必须以LWS_MAX_SMP大于 1 编译原文档明确说明 “lilbwebsockets must have been built withLWS_MAX_SMPgreater than 1 to use multiple threads”。LWS_MAX_SMP是编译期常量LWS_MAX_SMP 1默认值时 lws 只支持单线程服务相关 pthread 锁也不会编入。3. 事件库选择选项的优先级从源码main()中的if / else if链可以看出事件库选项存在优先级--uv--event--ev--glib。当所有事件库选项都未给出时示例注册SIGINT处理函数并回落至 lws 默认的poll()事件循环。此外源码还支持一个 README 未列出的--glib选项对应LWS_SERVER_OPTION_GLIB需要 lws 以 GLib 事件库支持编译。三、构建前提与步骤1. 依赖要求CMake 侧CMakeLists.txt 通过find_package(libwebsockets CONFIG REQUIRED)定位已安装的 lws并调用require_lws_config强制检查两项配置任何一项不满足都会跳过编译LWS_ROLE_H1HTTP/1.x 角色支持必须开启示例本质是一个 H1 服务器LWS_WITH_SERVER服务器端支持必须开启require_pthreads多线程示例依赖 pthread编译时需要链接PTHREAD_LIB。链接时若 lws 以共享库构建websockets_shared则链接websockets_shared与PTHREAD_LIB及LIBWEBSOCKETS_DEP_LIBS否则链接静态库websockets。2. 编译命令$ cmake . make3. 多线程能力的编译期开关如前所述示例要真正跑多线程宿主 libwebsockets 必须以LWS_MAX_SMP大于 1 构建。LWS_MAX_SMP同时决定了示例可用的最大线程数上限-t参数不能超过它lws 是否编入额外的 pthread 锁与 per-threadpt基础设施。另外若要以--uv/--event/--ev使用外部事件库lws 必须分别以-DLWS_WITH_LIBUV1、-DLWS_WITH_LIBEVENT1、-DLWS_WITH_LIBEV1配置编译否则对应选项虽可解析但 lws 内并无相应后端实现。四、核心源码逐段解析1. 静态文件挂载mountstatic const struct lws_http_mount mount { /* .mountpoint */ /, /* 挂载点 URL */ /* .origin */ ./mount-origin,/* 实际服务目录 */ /* .def */ index.html, /* 默认文件名 */ /* .origin_protocol */LWSMPRO_FILE, /* 来自目录中的文件 */ /* .mountpoint_len */ 1, /* mountpoint 字符数 */ };该结构把 URL 根路径/映射到启动目录下的./mount-origin目录未指定具体文件时默认返回index.html。info.error_document_404 /404.html指定了 404 错误页。因此访问不存在的页面例如首页中的 notextant.html 链接时会返回 mount-origin/404.html。2. context 创建信息info.port 7681; info.mounts mount; info.error_document_404 /404.html; info.pcontext context; info.signal_cb signal_cb; info.options LWS_SERVER_OPTION_HTTP_HEADERS_SECURITY_BEST_PRACTICES_ENFORCE;监听端口固定为7681启用LWS_SERVER_OPTION_HTTP_HEADERS_SECURITY_BEST_PRACTICES_ENFORCE即强制实施 HTTP 响应头安全最佳实践CSP 等安全响应头由 lws 自动附加首页中引用的strict-csp.svg正与此相关info.count_threads由-t决定默认 8在#if defined(LWS_WITH_TLS)保护下若传入-s选项会额外设置LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT并加载仓库内自带的localhost-100y.cert与localhost-100y.key从而让示例同时支持 HTTPS。3. 多线程服务循环SMP 的关键void *thread_service(void *threadid) { while (lws_service_tsi(context, 10000, (int)(lws_intptr_t)threadid) 0 !interrupted) ; pthread_exit(NULL); return NULL; }lws_service_tsi(context, timeout_ms, thread_index)是 SMP 模式下多线程服务循环的入口每个服务线程通过自己的thread_indexThread Service Index驱动事件循环超时值为 10000 毫秒。主线程在创建 context 后根据lws_get_count_threads(context)实际生效的线程数通过pthread_create逐个启动服务线程最后用pthread_join等待所有线程退出。4. 信号处理与优雅退出void signal_cb(void *handle, int signum) { interrupted 1; switch (signum) { case SIGTERM: case SIGINT: break; default: lwsl_err(%s: signal %d\n, __func__, signum); break; } lws_context_destroy(context); }收到SIGINT/SIGTERM时置位interrupted标志服务线程的 while 循环随即退出最后统一lws_context_destroy(context)销毁 context。注意当使用外部事件库--uv等时context 创建时传入的是signal_cb由事件库后端接管信号未使用外部事件库时示例才显式调用signal(SIGINT, sigint_handler)注册信号处理。五、SMP 多线程服务的工作原理要理解该示例的意义需要结合 lws 的 SMP 设计。相关机制在 minimal-http-server-smp 的 README 中有明确说明线程与 wsi 的绑定关系当有新的连接被 accept 后lws 会把它绑定到当前 wsi 数量最少的 ptper-thread 服务实例上以实现线程间负载均衡单线程独占服务一个 wsi 只能由它所绑定的那个服务线程来服务因此整个系统虽然可以同时服务与线程数等量的 wsi但单个 wsi 的读写始终固定在同一个线程上无需跨线程加锁竞争扩展效果取决于负载形态由于每个线程独立轮询事件循环多线程的收益主要体现在多连接、高并发场景README 建议配合ab等压测工具验证连接数较少时收益有限。从本示例源码看lws_get_count_threads(context)返回的实际线程数由LWS_MAX_SMP与info.count_threads共同决定服务线程启动数量严格以此为基准。这也解释了为什么构建 lws 时必须保证LWS_MAX_SMP 1——它决定了 SMP 基础设施与线程上限是否存在。六、运行与验证1. 启动$ ./lws-minimal-http-server-eventlib-smp [2018/03/04 09:30:02:7986] USER: LWS minimal http server-eventlib | visit http://localhost:7681 [2018/03/04 09:30:02:7986] NOTICE: Creating Vhost default port 7681, 1 protocols, IPv6 on [2018/03/04 09:30:02:7986] NOTICE: Service threads: 8日志中的Service threads: 8来自源码中的lwsl_notice( Service threads: %d\n, lws_get_count_threads(context))可用于确认 SMP 线程数是否按预期生效。2. 功能验证点默认首页访问http://localhost:7681返回mount-origin/index.html包含 lws logo 与 “Hello from the minimal http server event loop example” 文案404 页访问首页中提供的notextant.html链接或任意不存在的路径会返回404.html自定义错误页事件库切换分别以--uv、--event、--ev启动观察服务是否正常运行以此验证对应事件库后端是否编入线程数调整用-t 2等参数限制服务线程数配合日志确认实际生效值HTTPS若 lws 以 TLS 支持编译可用-s启动访问https://localhost:7681使用仓库自带的 100 年有效期本地证书。3. 运行示例$ ./lws-minimal-http-server-eventlib-smp -d15 -t 4 --uv以上命令表示日志级别 15、4 个服务线程、强制使用 libuv 事件库后端前提是 lws 已按-DLWS_WITH_LIBUV1构建。七、与其他官方示例的对比示例特点与本示例关系minimal-http-server基础单线程 HTTP 服务器默认 poll()本示例的基础形态minimal-http-server-eventlib支持事件库切换但为单线程本示例去 SMP 化后的版本二者命令行选项基本一致minimal-http-server-smp多线程服务但不支持外部事件库与 minimal-http-server-smp 的 README 对照阅读可完整理解 SMP 负载均衡与 wsi 绑定的设计本示例本质上是“事件库可插拔 SMP 多线程”两个特性的组合示范适合作为评估 lws 在不同事件循环后端与多线程调度策略下并发表现的起点。八、总结minimal-http-server-eventlib-smp用约 170 行 C 代码完整演示了 lws 的三项高级能力外部事件库后端可插拔libuv / libevent / libev / GLib或回落 poll()基于LWS_MAX_SMP 1的多线程服务通过lws_service_tsi()lws_get_count_threads()驱动 per-thread 事件循环静态文件挂载、404 错误页、TLS 与安全响应头等常用 HTTP 服务器功能。使用该示例前需明确三个前提lws 必须以LWS_MAX_SMP 1构建才能使用多线程使用特定事件库后端需对应LWS_WITH_LIBUV / LWS_WITH_LIBEVENT / LWS_WITH_LIBEV编译选项示例本身处于开发阶段、尚未稳定。在 TEN-framework 仓库中libwebsockets 作为第三方依赖见 third_party/libwebsockets/BUILD.gn被集成本文剖析的 SMP 与事件库机制可作为理解 lws 在宿主项目中服务调度行为的参考。赞分享人工智能AI Agent多模态语音AI 应用【免费下载链接】ten-frameworkOpen-source framework for conversational voice AI agents项目地址https://gitcode.com/TEN-framework/ten-framework点击查看免费下载相关推荐libwebsockets 最小 HTTP 服务器事件循环后端示例libuv / libev / libevent 一键切换实战解析libwebsockets 最小 HTTP 服务器事件循环后端示例libuv / libev / libevent 一键切换实战解析 libwebsocket人工智能AI Agent多模态语音AI 应用MCP Python SDK 服务端工具Tools开发指南用 mcp.tool() 把普通 Python 函数变成模型可调用的工具MCP Python SDK 服务端工具Tools开发指南用 mcp.tool 把普通 Python 函数变成模型可调用的工具 本指南基于 python人工智能AI Agent多模态语音AI 应用yay Lua钩子完整指南用SearchFilter与RenderAUR定制AUR搜索结果的10个实战技巧yay Lua钩子完整指南用SearchFilter与RenderAUR定制AUR搜索结果的10个实战技巧 yay 是 Arch Linux 上以 Go 语言人工智能AI Agent多模态语音AI 应用上一篇Self-LLM 实战案例集从 LoRA 微调到全栈大模型应用的四条完整链路下一篇终极炉石传说插件指南55项功能全面提升游戏体验创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考