ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

TEN-framework 中 libwebsockets Secure Streams 压力测试示例剖析:minimal-secure-streams-stress 并发与预算机制详解

TEN-framework 中 libwebsockets Secure Streams 压力测试示例剖析:minimal-secure-streams-stress 并发与预算机制详解 人工智能AI Agent多模态语音AI 应用【免费下载链接】ten-frameworkOpen-source framework for conversational voice AI agents项目地址https://gitcode.com/TEN-framework/ten-framework点击查看免费下载导读本文深入解析 TEN-framework 仓库中第三方网络库 libwebsockets 自带的压力测试示例minimal-secure-streams-stress位于 third_party/libwebsockets/minimal-examples/secure-streams/minimal-secure-streams-stress。它本质上是minimal-secure-streams的增强版通过**多进程并发concurrent与顺序预算budget**两种维度对 Secure StreamsSS连接进行压力测试。读完本文你将掌握该示例的构建方式、全部命令行参数语义、fork 并发与预算递减的底层实现、故障注入手段以及它在 libwebsockets 官方 CI 与 TEN-framework 构建体系中的真实定位。一、Secure Streams 与 stress 示例的定位libwebsockets 的 Secure Streams 是一套把连接策略policy与业务负载payload严格解耦的客户端 API业务代码只关心流类型名称streamtype与载荷本身而连接的一切策略——包括端点endpoint、TLS CA、乃至线级协议如 h1/h2——全部由创建lws_context时注入的**策略数据库policy database**决定见 secure-streams 目录 README。minimal-secure-streams-stress的定位与普通示例不同其 README 开宗明义它与minimal-secure-streams完全相同唯一区别在于你可以让它同时发起并发 SS 连接并设置一个顺序连接预算。简单来说它fork 出-c concurrent个进程每个进程依次执行--budget count次 SS 连接。这种设计让开发者可以验证大量并发 SS 连接同时建立时TLS 握手、策略解析、事件循环是否稳定验证单进程内连续多次建立/销毁连接的累积资源内存、fd、定时器是否泄漏配合故障注入选项检验重试与退避策略在压力下的表现。该示例与基础版 minimal-secure-streams 共用同一份源码minimal-secure-streams.c通过条件编译LWS_SS_USE_SSPC、LWS_WITH_SS_DIRECT_PROTOCOL_STR、LWS_WITH_SECURE_STREAMS_BUFFER_DUMP、LWS_WITH_SYS_METRICS在不同构建下呈现不同行为。二、工作原理fork 并发 × 顺序预算整个压力模型由两套正交的计数器组成源码位于 minimal-secure-streams.c2.1 并发维度-c concurrentmain()中通过 fork 创建并发进程int n 0, expected 0, concurrent 1; ... if ((p lws_cmdline_option(argc, argv, -c))) concurrent atoi(p); if (concurrent 0 || concurrent 100) return 1; ... for (n 0; n concurrent - 1; n) { if (fork()) { #if defined(WIN32) Sleep(1); #else usleep(1000); #endif lws_snprintf(cxname, sizeof(cxname), ctx%d, n 1); break; } }关键细节合法性校验concurrent取值必须位于[0, 100]区间越界直接返回 1防止 fork 风暴fork 即退出循环父进程 fork 出第一个子进程后立即break子进程继续下一轮循环再 fork 自己的子进程形成链式进程树最终共concurrent个进程各自独立运行进程间错峰fork 后usleep(1000)1ms错开各进程启动时刻避免同一瞬间发起海量 TLS 连接——这正是 CMake 测试中注释强调的防止服务器收到数千个同时 TLS 连接尝试。2.2 顺序预算维度--budget count每个进程通过create_ss()串行建立连接budget是全局计数器每创建一次连接递减static int create_ss(struct lws_context *cx) { lws_ss_info_t ssi; budget--; /* 每建一个 SS 消耗一个预算 */ ... ssi.handle_offset offsetof(myss_t, ss); ssi.opaque_user_data_offset offsetof(myss_t, opaque_data); ssi.rx myss_rx; ssi.tx myss_tx; ssi.state myss_state; ssi.user_alloc sizeof(myss_t); ssi.streamtype test_ots ? mintest-ots : (test_respmap ? respmap : mintest); if (lws_ss_create(cx, 0, ssi, NULL, NULL, NULL, NULL)) { lwsl_cx_err(context, failed to create ss); return -1; } ... }预算的消耗节奏由状态机回调驱动详见下一节每次连接结束LWSSSCS_DISCONNECTED或超时LWSSSCS_TIMEOUT时若budget仍大于 0 就调用create_ss()续接下一次连接预算耗尽则置interrupted 1退出事件循环。2.3 进程级总超时护栏每个进程还有一个整体超时防止某个连接挂死导致进程永不退出lws_sul_schedule(context, 0, sul_timeout, process_timeout, (lws_usec_t)((lws_usec_t)budget * (lws_usec_t)timeout_ms * LWS_US_PER_MS));即进程总超时 预算数 × 单连接超时默认 8000ms。超时回调process_timeout()打印process timed out后exit(1)并在退出前lws_sul_cancel(sul_timeout)取消定时器。三、命令行参数全表原 README 给出了 4 个核心参数以下结合源码将其扩充为完整参数表源码依据见main()中lws_cmdline_option的解析逻辑命令行选项含义源码依据-d loglevel调试日志级别十进制如-d15my_log_cx.lll_flags LLLF_LOG_CONTEXT_AWARE \| atoi(p)-c concurrent初始化时 fork 的进程数取值范围[0, 100]越界退出concurrent atoi(p)与范围校验--budget count每个 fork 进程顺序执行的 SS 连接次数默认 1budget atoi(p)--pass-limit count通过判定所需的最少成功连接数默认等于 budget做故障注入时可调低predicted_good atoi(p)--timeout_ms ms单个连接的超时毫秒数默认 8000timeout_ms (unsigned int)atoi(p)--force-portal强制让 SS 的 Captive Portal Detection 认为自己处于门户认证之后故障注入force_cpd_fail_portal 1--force-no-internet强制让检测认为自己无法访问互联网故障注入force_cpd_fail_no_internet 1--respmap使用respmapstreamtype 测试响应映射test_respmap 1--ots使用依赖操作系统信任库OS trust store的mintest-otsstreamtypetest_ots 1--expected-exit code预期退出码程序将实际退出码与之比对决定测试是否通过expected atoi(p)-p port仅 SSPC 构建通过指定 TCP 端口连接 ssproxy而非默认 UDSinfo.ss_proxy_port (uint16_t)atoi(p)-i iface仅 SSPC 构建指定 UDS 路径无-p时或要绑定的网络接口有-p时info.ss_proxy_bind p-a addr仅 SSPC 构建配合-p指定要连接的代理地址info.ss_proxy_address p其中--pass-limit的语义值得单独强调默认情况下通过线pass limit等于预算值即每个连接都必须成功但进行故障注入如--force-portal、--force-no-internet时部分连接按预期会失败此时应把 pass-limit 调低让测试以部分失败但符合预期的方式通过。程序退出前的判定逻辑为lwsl_user( good: %d / %d budget, pass limit %d\n, good, orig_budget, predicted_good); if (good predicted_good) bad 1;good在状态机收到LWSSSCS_QOS_ACK_REMOTE事务断言性成功时累加最终若good predicted_good则标记失败。四、状态机从 CREATING 到 DISCONNECTED 的完整流转myss_state()回调是整个示例的神经系统它通过lws_ss_state_name()打印每个状态并针对不同状态做出不同动作状态行为LWSSSCS_CREATING调用lws_ss_client_connect()发起连接LWSSSCS_CONNECTING启动单连接超时lws_ss_start_timeout(m-ss, timeout_ms)通过lws_ss_set_metadata()设置uptag、ctype等元数据OOM 时返回LWSSSSRET_DISCONNECT_ME稍后重试LWSSSCS_ALL_RETRIES_FAILED重试全部耗尽interrupted 1; bad 2;失败码 2LWSSSCS_CONNECTED直接协议串构建下遍历读取server:、content-security-policy:等 8 个响应头元数据LWSSSCS_QOS_ACK_REMOTE事务断言性成功goodLWSSSCS_QOS_NACK_REMOTE事务断言性失败等待 DISCONNECTED 继续LWSSSCS_DISCONNECTED预算未耗尽则create_ss()续接否则interrupted 1返回LWSSSSRET_DESTROY_MELWSSSCS_TIMEOUTbad 3同样按预算决定续接或结束LWSSSCS_USER_BASE打印LWSSSCS_USER_BASE通知接收路径myss_rx()判定结束条件收到LWSSS_FLAG_EOM消息尾即认为完整收到页面置bad 0LWSSS_FLAG_PERF_JSON直接返回 OK用于性能模式。发送路径myss_tx()本例不发送数据直接返回LWSSSSRET_TX_DONT_SEND。由此可归纳该示例的失败码约定失败码含义0成功收到完整消息EOM1成功连接数不足 pass-limit或发生其他非特指错误2所有重试均失败3单连接超时进程级exit(1)进程整体超时预算 × 单连接超时五、内嵌策略数据库重试、证书与容错在非 SSPC直接构建模式下示例通过info.pss_policies_json default_ss_policy把整份 JSON 策略内嵌到客户端。这份策略值得细读它是 Secure Streams策略驱动连接的典型样本retry命名退避策略defaultbackoff序列[1000, 2000, 3000, 5000, 10000]毫秒、conceal: 5、jitterpc: 20±20% 抖动、svalidping: 30、svalidhup: 35——压力测试中连接失败时按此序列退避重试certs与trust_stores内嵌 ISRG Root X1Lets Encrypt 根证书BASE64 DER 形式并定义命名信任链le_via_isrg定义FORCE_OS_TRUST_STORE可改用操作系统信任库s流定义fetch_policy流负责从warmcat.com:443用 h1 协议GET拉取真实策略policy/minimal-proxy-v4.2-v2.jsonopportunistic: true表示该流是机会性可选的启用LWS_WITH_SS_DIRECT_PROTOCOL_STR时则改为直接定义mintest流captive_portal_detect访问connectivitycheck.android.com/generate_204http_expect: 204http_fail_redirect: true用于检测是否处于门户认证captive portal之后——这正是--force-portal/--force-no-internet故障注入所操纵的环节。5.1 故障注入的实现方式策略叠加--force-portal与--force-no-internet通过lws_ss_policy_overlay()在运行时叠加覆盖策略中的captive_portal_detect流if (force_cpd_fail_portal) /* 让检测看起来像在门户之后覆盖为 google.com:80 且会重定向 */ lws_ss_policy_overlay(context, {\s\: [{\captive_portal_detect\: { \endpoint\: \google.com\, \http_url\: \/\, \port\: 80 }}]}); if (force_cpd_fail_no_internet) /* 让检测看起来像无网络覆盖为 warmcat.com:999无人监听 */ lws_ss_policy_overlay(context, {\s\: [{\captive_portal_detect\: { \endpoint\: \warmcat.com\, \http_url\: \/\, \port\: 999 }}]});从源码注释可以确认前者利用覆盖地址会发生重定向制造门户假象后者利用覆盖端口上没有任何服务制造断网假象。两个选项在main()中被明确标注为互斥mutually exclusive。六、构建与前置条件6.1 本地 CMake 构建原 README 给出的构建命令极简$ cmake . make从 CMakeLists.txt 可见其依赖的 libwebsockets 编译特性require_lws_config硬性检查特性宏要求说明LWS_ROLE_H11需要 h1 角色LWS_WITHOUT_CLIENT0不能禁用客户端LWS_WITH_SECURE_STREAMS1必须启用 Secure StreamsLWS_WITH_SECURE_STREAMS_STATIC_POLICY_ONLY0必须允许运行时拉取/叠加策略LWS_WITH_SYS_STATE1需要系统状态管理同时该示例不支持 Windowsif (NOT WIN32)包裹了全部构建逻辑。构建产物有两个lws-minimal-secure-streams-stress直接构建客户端内嵌完整策略独立完成连接lws-minimal-secure-streams-stress-client仅当库编译带LWS_WITH_SECURE_STREAMS_PROXY_API时生成编译期注入-DLWS_SS_USE_SSPC客户端自身不含策略、不初始化 TLS通过 Unix Domain Socket 连接到同机的lws-minimal-secure-streams-proxy见 minimal-secure-streams-proxy完成连接代理默认监听 Linux abstract namespace 下的 UDSproxy.ss.lws。6.2 在 TEN-framework 中的构建集成TEN-framework 将 libwebsockets 作为third_party依赖纳入 GN 构建体系见 third_party/libwebsockets/BUILD.gn通过cmake_project(websockets)在构建时用 CMake 编译整个库安装头文件与库文件到${root_gen_dir}/cmake/websockets/install/依赖mbedtls实现 TLSLWS_WITH_MBEDTLSON并通过websockets_copy_mbedtls拷贝 mbedtls 头文件明确关闭了与本示例相关的部分LWS_WITH_HTTP2OFF注释说明 h1 需在同一帧内发送头与体、LWS_WITHOUT_TESTAPPSON禁用测试应用编译等——这意味着在 TEN 的正式构建产物中本 stress 示例作为上游参考源码随 third_party 一并纳入仓库但不作为测试应用被编译产出其 CTest 用例是 libwebsockets 自身 CI 体系的组成部分。值得一提的是TEN 仓库中 libwebsockets 的实际 API 消费点在packages/example_extensions/simple_http_server_cpp/src/main.ccmain.cc该 HTTP server extension 直接使用lws_create_context()/lws_service()/lws_http_transaction_completed()等 libwebsockets 接口其编译依赖在 tests/common/server/cpp/BUILD.gn 与 tests/ten_runtime/smoke/http_server_extension/BUILD.gn 中均声明为//third_party/libwebsockets。这印证了 libwebsockets 在 TEN 中的角色——为网络相关 extension 提供底层 HTTP/WS 事件循环能力。七、官方 CI 测试stress 用例是如何被执行的CMakeLists 中注册了ssstress-warmcat与sspc-minimalstress两个 CTest 用例直接体现了该示例的推荐运行参数# 直接模式4 个并发进程 × 每进程 5 个顺序连接 add_test(NAME ssstress-warmcat COMMAND lws-minimal-secure-streams-stress -c 4 --budget 5) set_tests_properties(ssstress-warmcat PROPERTIES TIMEOUT 60) # 代理SSPC模式通过 UDS 连接测试代理同样 4×5 add_test(NAME sspc-minimalstress COMMAND lws-minimal-secure-streams-stress-client -i ${CTEST_SOCKET_PATH} -c 4 --budget 5) set_tests_properties(sspc-minimalstress PROPERTIES TIMEOUT 40)测试编排上有几个值得借鉴的工程细节资源租约Sai resource leasesai_resource(warmcat_conns 1 40 sspcmin)让 CI 在跑测试前对warmcat.com连接资源加锁 40 秒避免数千个同时 TLS 连接冲击远端服务器代理夹具fixturesst_ssstressproxyctest-background.sh拉起测试代理与ki_ssstressproxyctest-background-kill.sh回收代理构成FIXTURES_SETUP/FIXTURES_CLEANUP客户端用例通过FIXTURES_REQUIRED依赖它们Linux 下 UDS 使用ctest-sspstress-...抽象命名空间地址Valgrind 内存检查检测到valgrind时用例自动切换为valgrind --toolmemcheck --leak-checkyes --num-callers20 ... -c 4 --budget 5配合-c/--budget的多次连接专门用于暴露 SS 长连接场景下的内存泄漏。八、一次典型运行的预期输出形态以基础版 minimal-secure-streams README 的日志为参照正常一次连接的状态流转大致为USR: myss_state: LWSSSCS_CREATING, ord 0x0 USR: myss_state: LWSSSCS_CONNECTING, ord 0x0 N: lws_ss_client_connect: connecting h1get warmcat.com / USR: myss_state: LWSSSCS_CONNECTED, ord 0x0 USR: myss_rx: len 1024, flags: 1 ← 数据分片到达 USR: myss_rx: len 0, flags: 2 ← LWSSS_FLAG_EOM消息接收完毕 USR: myss_state: LWSSSCS_DISCONNECTED, ord 0x0 USR: myss_state: LWSSSCS_DESTROYING, ord 0x0 USR: Completed: OKstress 变体与之的差异在于每个 fork 进程的日志会写入各自独立的文件/tmp/ctx0.log、/tmp/ctx1.log……源码中lws_snprintf(logpath, /tmp/%s.log, cxname)且info.vhost_name cxname使上下文名称与日志一一对应便于并行排查各进程状态程序最终打印good: %d / %d budget, pass limit %d若good达到predicted_good且退出码与--expected-exit一致则输出Completed: OK (seen expected %d)并返回 0否则返回 1。九、实践建议与适用场景综合源码与 CI 用法可将该示例的典型使用方式归纳如下基准压力./lws-minimal-secure-streams-stress -c 4 --budget 5即官方 CI 采用的 4 进程 × 5 连接组合排查内存泄漏在 valgrind 下运行并加大--budget观察多次顺序连接后堆是否持续增长验证重试与退避--force-portal或--force-no-internet配合--pass-limit调低通过线观察backoff序列是否按策略逐步退避、ALL_RETRIES_FAILED是否正确置失败码 2代理链路验证先运行lws-minimal-secure-streams-proxy再以-client变体-i uds路径 -c N --budget M连接之可检验无策略客户端 策略代理的 SSPC 分离架构在并发下的稳定性CI 门禁借助--expected-exit把退出码断言嵌入自动化测试用成功数 ≥ pass-limit 且退出码符合预期作为通过标准。需要说明的边界该示例依赖外网可达的warmcat.com默认端点离线环境或网络受限场景下连接将按退避策略重试直至失败此时请配合--pass-limit、--expected-exit设计符合预期的判定。在 TEN-framework 仓库内本示例以 third_party 上游参考源码形式存在直接以 CMake 独立构建并运行即可复现上述全部行为。输出文章结束全文完赞分享人工智能AI Agent多模态语音AI 应用【免费下载链接】ten-frameworkOpen-source framework for conversational voice AI agents项目地址https://gitcode.com/TEN-framework/ten-framework点击查看免费下载相关推荐lyric-view-cj文件加载歌词教程FileParser自动识别CR/LF/CRLF换行符新手完整指南lyric view cj文件加载歌词教程FileParser自动识别CR/LF/CRLF换行符新手完整指南 lyric view cj 是一个可关联音乐播人工智能AI Agent多模态语音AI 应用libwebsockets Secure Streams 客户端实战api-test-secure-streams 测试程序原理与源码解析libwebsockets Secure Streams 客户端实战api test secure streams 测试程序原理与源码解析 本文以 TEN f人工智能AI Agent多模态语音AI 应用Xinference 部署 llama-3-instruct 完全指南模型规格、量化选项与多引擎启动命令详解Xinference 部署 llama 3 instruct 完全指南模型规格、量化选项与多引擎启动命令详解 本文基于 Xinference 内置模型文档 l人工智能AI Agent多模态语音AI 应用上一篇Internationalizing Go Web Applications with go-i18n: Multi-Locale Management and Template MapFuncs下一篇基于 Context Engineering 的 PRP 生成深入解析 Claude Code 自定义斜杠命令 /generate-prp创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表