news 2026/9/29 5:42:32

libwebsockets 故障注入(lws_fi)完全指南:构建选项、规则语法与内置故障清单

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
libwebsockets 故障注入(lws_fi)完全指南:构建选项、规则语法与内置故障清单
  • 人工智能
  • AI Agent
  • 多模态
  • 语音
  • AI 应用

【免费下载链接】ten-framework

Open-source framework for conversational voice AI agents

项目地址:https://gitcode.com/TEN-framework/ten-framework
点击查看免费下载

lws_fi(Fault Injection)是 libwebsockets 提供的一套"系统性故障注入"机制:它在构建期通过LWS_WITH_SYS_FAULT_INJECTION选项开启,允许开发者在任意 lws 内部代码或用户代码中,按名称精准地合成 DNS 失败、连接失败、OOM、发送失败等难以在测试期自然复现的故障,从而验证错误处理路径的正确性。本文以 README.fault-injection.md 为骨架,结合 lws-fault-injection.h 与 fault-injection.c 的源码实现,系统讲解其设计原理、注入策略、命名空间继承、命令行接入方式,并给出完整的"已知内置故障名"清单,读者可据此在自己的 lws 应用或测试中直接复现各种故障场景。

上图展示了 lws_fi 的核心思想:用户准备好的故障规则(lws_fi_ctx_t)既可以绑定到lws_context,再经由lws_vhost、Secure Stream 等子对象逐级继承分发,也可以直接附加到客户端wsi或 Secure Stream 对象上;故障规则会沿匹配的每个层级向下传播到子对象(Faults propagate into subobjects at each matching level)。

为什么需要故障注入

日常开发中,绝大部分精力都花在"让系统在正常运行时做它该做的事"上。但若要保证质量,仅仅测试正常路径是不够的:那些低概率的错误分支(例如清理了尚未初始化的资源、忘记释放内存等)在测试期极难自然触发,却又往往是线上事故的根源。

lws 故障注入的目标就是解决这一痛点:它提供简单而强大的 API,允许在任何 lws 或用户代码中定向注入故障——包括早期初始化阶段,甚至 lws 初始化之前的用户代码。同时,lws 内部预置了大量"知名故障点"(well-known faults),可以从外部直接触发,无需修改被测代码。

核心概念:故障上下文与故障

故障注入的基本模型是:用户代码中的对象可以选择在自身内部初始化"故障上下文"(fault contexts),该上下文列出一组命名清晰的"故障"(faults),代表该代码支持、且用户希望注入的故障类型。

从 lws-fault-injection.h 可以看到两个核心数据结构:

typedef struct lws_fi { const char *name; /* 故障名称 */ const uint8_t *pattern; /* PATTERN 类型的位模式 */ uint64_t pre; /* DETERMINISTIC: 前置次数;PROBABILISTIC: 百分比;RANGE: 范围下限 */ uint64_t count; /* DETERMINISTIC: 注入次数;PATTERN: 位宽;RANGE: 范围上限 */ uint64_t times; /* 起始为 0,记录被查询的次数 */ char type; /* LWSFI_* 注入策略类型 */ } lws_fi_t; typedef struct lws_fi_ctx { lws_dll2_owner_t fi_owner; /* lws_fi_t 的双链表 */ struct lws_xos xos; /* xoshiro256 PRNG 状态(用于概率类注入) */ const char *name; } lws_fi_ctx_t;
  • lws_fi_t:一条故障注入规则。每次注入请求都由它描述——注入哪个故障(name),以及"何时、以多大概率"注入(type+pre/count/pattern/times)。
  • lws_fi_ctx_t:故障上下文,本质是lws_fi_t对象构成的链表(lws_dll2_owner_t fi_owner),内嵌一个 xoshiro256 伪随机数生成器状态,用于概率类决策。

这些"故障上下文"既可以直接嵌入对象(例如嵌入lws_context创建信息结构体、客户端连接信息结构体或 Secure Stream 信息结构体),也可以在对象创建后由系统对象携带。启用故障注入构建后,lws_context、lws_vhost、wsi、Secure Stream 句柄 / SSPC 句柄等关键系统对象都各自持有自己的lws_fi_ctx_t链表,可以挂接任意数量的lws_fi_t。

不过,直接向深层代码传参往往并不方便。例如:想在一个由 Secure Stream 创建的 wsi 上触发故障,该 wsi 由 lws 内部代码创建,与 Secure Stream 对象创建隔了一层,难以在创建时直接附加。因此 lws_fi 设计了基于命名空间路径(namespace paths)的定向继承方案:通常只需在 context 创建时列出想要的故障,它们就会在后续创建内部对象时被过滤分发到目标对象上。这也正是 fault-injection.c 中lws_fi_inherit_copy()的实现职责:按 scope(如vh)与 value(如myvhost)匹配vh=myvhost/前缀的规则,去掉匹配前缀后把副本挂到目标故障上下文。

构建选项:LWS_WITH_SYS_FAULT_INJECTION

lws_fi 通过一个构建期选项开启,默认关闭。在仓库的 CMakeLists.txt 中:

option(LWS_WITH_SYS_FAULT_INJECTION "Enable fault injection support" OFF)

在编译 lws 时可通过-DLWS_WITH_SYS_FAULT_INJECTION=ON(或环境变量LWS_WITH_SYS_FAULT_INJECTION=1)打开。

需要强调的是默认行为零副作用:仅开启构建选项并不会影响代码运行,因为用户还必须显式地把想要的故障规则加入对象的故障上下文,故障才会被注入。此外,当该选项被关闭时,lws_fi()调用以及所有公开的lws_fi_user_*_fi()API 都会退化为编译期常量(0)(见 lws-fault-injection.h),相关判断代码会被编译器整体移除,零运行时开销。

在 lws 私有代码中集成故障条件

lws 私有代码中最简单的查询接口是:

lws_fi(fi_ctx, "name")
  • 返回0:本次不需要注入故障;
  • 返回1:本次应当合成该故障。

如果上下文中没有匹配"name"的规则,则总是返回0(不注入)。从 fault-injection.c 的实现可以看到,lws_fi()先在上下文的链表中查找同名规则,找不到直接返回 0;找到后按规则的type字段执行对应的决策逻辑,决定注入时还会打印一条告警日志Injecting fault %s->%s(这正是文档示例中日志的来源)。同时,若构建期禁用了故障注入,lws_fi()恒为常量0,代码中已有的lws_fi()调用可以原样保留、由编译器消除。

在用户代码中使用公开 API

用户代码无需理解故障上下文内部结构,只要手握一个常见对象(如 wsi)与规则名称即可查询。lws 提供了四组公开 API:

故障上下文持有者公开 API
lws_contextint lws_fi_user_context_fi(struct lws_context *ctx, const char *rule)
wsiint lws_fi_user_wsi_fi(struct lws *wsi, const char *rule)
ss 句柄int lws_fi_user_ss_fi(struct lws_ss_handle *h, const char *rule)
sspc 句柄int lws_fi_user_sspc_fi(struct lws_sspc_handle *h, const char *rule)

它们的底层实现(fault-injection.c)其实就是对各自对象内嵌fic调用lws_fi()。

实战示例:minimal-http-client

仓库中的 minimal-http-client.c 在LWS_CALLBACK_ESTABLISHED_CLIENT_HTTP回调中就有这样一段用户代码:

if (lws_fi_user_wsi_fi(wsi, "user_reject_at_est")) return -1;

即:当规则wsi/user_reject_at_est命中时,在连接建立(ESTABLISHED)阶段主动返回-1拒绝连接。运行它并注入该故障:

lws-minimal-http-client --fault-injection 'wsi/user_reject_at_est'

运行日志(示意)如下:

... [2021/03/11 13:41:05:2769] U: Connected to 46.105.127.147, http response: 200 [2021/03/11 13:41:05:2776] W: lws_fi: Injecting fault unk->user_reject_at_est [2021/03/11 13:41:05:2789] E: CLIENT_CONNECTION_ERROR: HS: disallowed at ESTABLISHED ...

可以看到:连接本身成功(HTTP 200),随后故障被注入,连接因"在 ESTABLISHED 阶段被拒绝"而报出CLIENT_CONNECTION_ERROR,完整地走了一遍错误路径。

注入"时机"策略(LWSFI_* 类型)

lws_fi_t.type字段决定"何时注入"。API 会记录每次被查询的次数(times),并根据规则类型做出决策。源码 fault-injection.c 中的 switch 分支与头文件 lws-fault-injection.h 中的枚举一一对应:

注入规则类型描述
LWSFI_ALWAYS无条件注入故障
LWSFI_DETERMINISTIC在前pre次不注入之后,接下来count次每次都注入
LWSFI_PROBABILISTIC以pre百分比概率注入
LWSFI_PATTERN以pre指向的位模式为参考(count个 bit),某次查询对应的 bit 为 1 则注入,指向静态数组
LWSFI_PATTERN_ALLOC同PATTERN,但模式数组为动态分配,故障上下文销毁时释放
LWSFI_RANGE不用于lws_fi()决策,而是在pre与count之间取一个伪随机数

实现细节:

  • DETERMINISTIC:times自增后,落在[pre, pre+count)区间内才注入;
  • PROBABILISTIC:调用lws_xos_percent(&fic->xos, pre),即 PRNG 结果% 100 < pre时注入,100 恒真、0 恒假,中间线性缩放;
  • PATTERN / PATTERN_ALLOC:取times++ % count作为 bit 下标,pattern[n >> 3] & (1 << (n & 7))为真则注入;
  • RANGE:返回pre + (lws_xos(&fic->xos) % (count - pre)),从外部给定的123..456范围中取数(见lws_fi_range(),fault-injection.c)。

概率选择来源于 PRNG,其种子在 context 创建信息结构的故障注入上下文中设置。默认情况下,lws 辅助函数lws_cmdline_option_handle_builtin()把种子设为当前时间(微秒),但可以用--fault-seed <decimal>覆盖;命令行选项首次解析时会把实际生效的 PRNG 种子记入日志,便于复现。

向 lws_fi_ctx_t 添加故障规则

通常把lws_context作为定义故障的中央顶层位置。做法是在栈上准备好一个lws_fi_t,再逐一通过lws_fi_add(lws_fi_ctx_t *fic, const lws_fi_t *fi)把它加入 context 创建信息结构体的.fic成员。lws_fi_add()会分配内存、拷贝传入的fi并挂到lws_fi_ctx_t链表上,因此传入的fi可以安全地离开作用域(fault-injection.c)。

当 context(或其他使用同一机制的对象)被创建时,它会从信息结构体的.fic导入全部故障并接管所有权,随后把.fic清空,使其可以安全地随 info 结构体离开作用域。这一"转移"由lws_fi_import()完成——它还会顺带继承源上下文的 PRNG 种子(fault-injection.c)。

配套的辅助 API 还有:

  • lws_fi_remove(fic, name):按名移除并销毁一条规则;
  • lws_fi_destroy(fic):清空该上下文中所有已分配的规则(PATTERN_ALLOC模式会先释放模式数组);
  • lws_fi_inherit_copy(fic_dest, fic_src, scope, value):按 scope/value 匹配父上下文中的命名空间规则并拷贝给子对象(命名空间机制的核心实现);
  • lws_fi_deserialize(fic, sers):把字符串形式的规则(如"ss=captive_portal_detect/wsi/dnsfail(10%)")解析成lws_fi_t加入上下文(fault-injection.c)。

规则的传入时机:必须在对象创建之前

故障注入的一个关键要求是:规则必须在创建对象的代码面前可用,早于对象被创建。这就是为什么用户代码要在创建信息结构体中预先准备好故障上下文、列出规则,而不是等对象创建后再附加——那时再去测试创建期间的故障已经太迟了。

直接应用故障上下文

创建以下四类对象时,可以直接传入一个预先用lws_fi_t准备好的故障上下文:

被创建的对象信息结构体故障上下文成员
lws contextstruct lws_context_creation_infofic
vhoststruct lws_context_creation_infofic
Secure Streamstruct lws_ss_infofic
客户端 wsistruct lws_client_connect_infofic

例如在 lws-context-vhost.h 中,struct lws_context_creation_info在LWS_WITH_SYS_FAULT_INJECTION条件下带有lws_fi_ctx_t fic;成员;lws-client.h 中struct lws_client_connect_info同样带有fic以及一个与构建选项无关、始终可用的fi_wsi_name成员。

不过实践中更常用的做法是:只在 context 创建时给出故障列表,让对象通过命名空间匹配并继承——这就是下一节的内容。

用命名空间精准定位实例

直接创建的 vhost、Secure Stream 或 wsi 可以在创建时直接挂接子规则,无需命名空间。命名空间用于你只握有更上层对象(如lws_context)的创建时机、而目标对象由它内部创建、你没有直接句柄的场景——例如想在某个 vhost 的监听 socket 上触发故障。

命名空间采用/path/形式,规则名可以带上前缀,使后创建的对象继承:

命名空间形式效果
vh=myvhost/子规则名为 "myvhost" 的 vhost 被创建时继承该子规则
vh/子规则任意 vhost 被创建时继承该子规则
ss=mystream/子规则streamtype 为 "mystream" 的 SS 继承(也覆盖 SSPC / proxy 客户端)
ss/子规则任意 streamtype 的所有 SS 继承(也覆盖 SSPC / proxy 客户端)
wsi=myname/子规则以info->fi_wsi_name为 "myname" 创建的客户端 wsi 继承
wsi/子规则任意 wsi 继承

命名空间可以组合。例如vh=myvhost/wsi/listenskt:在服务器 vhost "myvhost" 创建的 wsi 上设置listenskt故障,即让该 vhost 的监听 socket 在创建时报错。

值得注意的细节:h2 连接上的网络连接 wsi 被迁移为 SID 1 时(wsi migration),其上已挂接的故障也会一并迁移。

各对象的继承来源一览

对象类型初始化的来源从何处继承匹配的故障
contextstruct lws_context_creation_info.fic-
vhoststruct lws_context_creation_info.ficcontext FIC
客户端 wsistruct lws_client_connect_info.ficcontext FIC, vhost FIC
ss / sspclws_ss_info_t.ficcontext FIC
ss / sspc 的 wsi-context FIC, vhost FIC, ss / sspc .fic

由于所有对象都能直接或通过逐级继承从lws_context的故障上下文触达,而从外部又最方便在 context 上设置规则,因此context 通常是所有注入故障的原始来源。

与 minimal 示例的集成:--fault-injection 与 --fault-seed

所有使用lws_cmdline_option_handle_builtin()API 的 minimal 示例都能额外接收--fault-injection "...,..."开关:该开关会自动解析参数中的逗号分隔列表,把给出的故障名加入lws_context。例如:

lws-minimal-http-client --fault-injection "wsi/dnsfail"

会强制该次运行中所有 wsi 的 DNS 查询失败。

从 libwebsockets.c 可以看到,内建命令行选项数组包含-d、--fault-injection、--fault-seed、--ignore-sigterm四项;解析到--fault-injection时调用lws_fi_deserialize(&info->fic, p)把字符串解析成规则,解析到--fault-seed时把十进制字符串转为 64 位种子(libwebsockets.c)。

指定"何时"注入的语法

默认情况下,如果只给出名称部分,只要命名空间缺失或匹配到对象,故障就会每次注入。也可以用括号附加额外信息,实现随机概率或循环模式注入:

语法配合使用含义
wsi/thefaultlws_fi()每次都注入故障
wsi/thefault(10%)lws_fi()以 10% 概率随机注入
wsi/thefault(.............X.X)lws_fi()每 16 次尝试中,在第 14 和第 16 次注入
wsi/thefault2(123..456)lws_fi_range()在 123 与 456 之间取一个数

注意:包含这些符号的字符串必须用引号包裹,否则可能被 shell 解释。pattern 中的.表示"该次不注入",X表示"该次注入"。

最后一个示例((123..456))并不像其他示例那样通过lws_fi()决定是否注入,而是配合lws_fi_range()使用,作为故障处理流程中的一个次级故障名。典型场景:先用myfault配合lws_fi()决定何时注入故障,再用第二个相关故障名myfault_delay为故障动作引入一个外部给定范围内的随机延迟(毫秒级):

"myfault(10%),myfault_delay(123..456)"

代码中调用lws_fi_range()查询myfault_delay,即可拿到 123~456 之间的伪随机数,用于控制延迟等参数(见lws_fi_range()的文档注释 lws-fault-injection.h)。

lws 内置的知名故障名清单

lws 内部预置了大量可在外部直接触发的故障点,覆盖 context 创建、vhost 创建、客户端连接、UDP、Secure Streams(ss / sspc / ssproxy)等各层次:

范围命名空间名称故障效果
contextctx_createfail1进入时立即让 context 创建失败
contextctx_createfail_plugin_init让 context 创建失败,如同插件初始化失败(启用插件时)
contextctx_createfail_evlib_plugin让 context 创建失败,如同事件库插件初始化失败(启用 evlib 插件时)
contextctx_createfail_evlib_sel让 context 创建失败,如同无法选择事件库
contextctx_createfail_oom_ctx让 context 创建因 context 对象 OOM 而失败
contextctx_createfail_privdrop让 context 创建因权限降级失败而失败
contextctx_createfail_maxfds让 context 创建因无法确定进程 fd 上限而失败
contextctx_createfail_oom_fds让 context 创建因 fds 表 OOM 而失败
contextctx_createfail_plat_init让 context 创建因平台初始化失败而失败
contextctx_createfail_evlib_init让 context 创建因事件库初始化失败而失败
contextctx_createfail_evlib_pt让 context 创建因事件库 pt 初始化失败而失败
contextctx_createfail_sys_vh让 context 创建因系统 vhost 创建失败而失败
contextctx_createfail_sys_vh_init让 context 创建因系统 vhost 初始化失败而失败
contextctx_createfail_def_vh让 context 创建因默认 vhost 创建失败而失败
contextctx_createfail_ss_pol1让 context 创建因 ss 策略解析开始失败而失败(启用策略时)
contextctx_createfail_ss_pol2让 context 创建因 ss 策略解析失败而失败(启用策略时)
contextctx_createfail_ss_pol3让 context 创建因 ss 策略设置失败而失败(启用策略时)
contextcache_createfail让lws_cache创建因 OOM 失败
contextcache_lookup_oom让lws_cache查找因 OOM 失败
vhostvhvh_create_oomvh 创建时对象分配 OOM
vhostvhvh_create_pcols_oomvh 创建时协议表分配 OOM
vhostvhvh_create_access_log_open_failvh 创建因无法打开访问日志而失败(LWS_WITH_ACCESS_LOG)
vhostvhvh_create_ssl_srv服务端 ssl_ctx 初始化失败
vhostvhvh_create_ssl_cli客户端 ssl_ctx 初始化失败
vhostvhvh_create_srv_init服务器初始化失败
vhostvhvh_create_protocol_init延迟协议初始化失败(用于延迟创建的 vhost)
服务端 vhostvh=xxx/wsilistenskt让 vhost 监听 socket 的socket()分配失败
客户端 wsiwsidnsfail同步:不调用getaddrinfo()并合成EAI_FAIL返回;异步:请求不启动并立即合成失败
客户端 wsiwsisendfail在 wsi socket 上发送数据失败
客户端 wsiwsiconnfail在 wsi socket 上连接失败
客户端 wsiwsicreatefail创建客户端 wsi 本身失败
udp wsiwsiudp_rx_loss丢弃实际收到的 UDP RX,配合概率模式使用
udp wsiwsiudp_tx_loss丢弃 UDP TX 使其不被真正发送,配合概率模式使用
服务端 ssssss_srv_vh_fail强制 Secure Streams 服务端 vhost 创建失败
客户端 ssssss_no_streamtype_policy让该 streamtype 的策略看似缺失
sspcsssspc_fail_on_linkup听到代理连接成功时拒绝该连接,引发无限重试
sspcsssspc_fake_rxparse_disconnect_me让客户端-代理链路解析看似请求断开,引发无限重试
sspcsssspc_fake_rxparse_destroy_me让客户端-代理链路解析看似请求销毁 SS,将干净地销毁 SS
sspcsssspc_link_write_fail强制链路写入失败,引发无限重试
sspcsssspc_create_oom让 sspc 句柄分配在创建时如同 OOM 失败
sspcsssspc_fail_metadata_set让 metadata 分配失败
sspcsssspc_rx_fake_destroy_me让客户端的用户代码rx()看似返回 DESTROY_ME
sspcsssspc_rx_metadata_oom让来自代理的 metadata 分配失败
ssproxyssssproxy_dsh_create_oom让代理的 DSH 创建失败
ssproxyssssproxy_dsh_rx_queue_oom让 SS->P[->C] DSH rx 方向的分配如同 OOM 失败,导致后续连接断开
ssproxywsissproxy_client_adopt_oom让代理无法为新客户端-代理链路连接对象分配内存
ssproxywsissproxy_client_write_fail让代理对客户端的写入失败
ssproxywsisspc_dsh_ss2p_oom让 ss->proxy dsh 分配失败
ssproxyssssproxy_onward_conn_fail让代理的后续客户端连接立即失败
ssproxyssssproxy_dsh_c2p_pay_oom让代理的 C->P payload DSH 分配失败
ssssss_create_smdSMD:ss 创建时 smd 注册失败
ssssss_create_vhost服务端:ss 创建时看似没有匹配 typename 的 vhost(仅!vhost)
ssssss_create_pcol服务端:ss 创建时看似策略中未给出协议
ssssss_srv_vh_fail服务端:ss 创建时看似无法创建 vhost
ssssss_create_destroy_mess 创建时看似 CREATING 状态返回了 DESTROY_ME
ssssss_create_no_ts静态策略:ss 创建时看似没有 trust store
ssssss_create_smd_1SMD:ss 创建时看似 CONNECTING 说了 DESTROY_ME
ssssss_create_smd_2SMD:ss 创建时看似 CONNECTED 说了 DESTROY_ME
ssssss_create_connNailed up:ss 创建时客户端连接以 DESTROY_ME 失败
wsiwsitimedclose让 wsi 在一段时间后关闭(配合下一个使用)
wsiwsitimedclose_mstimedclose的毫秒范围(如"timedclose_ms(10..250)")

这些故障名与文档、fault-injection.c 中的实现一一对应;实际触发时,lws 会在日志中打印Injecting fault告警,便于确认故障确实被注入。

已知的命名空间目标:内部 wsi 与自定义 wsi 名

命名空间可以更精准地定位目标。即便只把故障传给lws_context,也能用命名空间"路径"只针对特定来源创建的 wsi。

要定位 SS 连接产生的 wsi,可使用ss=stream_type_name/。以 captive portal 检测(CPD)为例:

ss=captive_portal_detect/ss_no_streamtype_policy # 让 CPD 找不到策略条目,从而禁用 CPD ss=captive_portal_detect/wsi/dnsfail # 让 CPD 无法解析服务器 DNS,看起来"没有网络" ss=captive_portal_detect/wsi/connfail # 针对 CPD 的连接测试部分,同样让 CPD 认为"没有网络"

内部 wsi 类型名

lws 为内部功能(如异步 DNS 处理)创建的 wsi 也可以被精准定位:

wsi 目标含义
wsi=asyncdns/lws 异步 DNS 支持用来与 DNS 服务器通信的 UDP wsi
wsi=dhcpc/lws DHCP 客户端使用的 UDP wsi
wsi=ntpclient/lws NTP 客户端使用的 UDP wsi

例如在lws_context级别传入wsi=asyncdns/udp_tx_loss,将抑制异步 DNS 的 UDP 发送,从而强制其无法解析任何域名。

对于用户自己创建的 wsi,可以在客户端连接创建时,把客户端创建信息结构体的.fi_wsi_name设置为字符串 "xxx"(lws-client.h),之后就能用wsi=xxx/命名空间只对这批 wsi 生效。minimal-http-client 中i.fi_wsi_name = "user"(minimal-http-client.c)正是为此,配合wsi/user_reject_at_est等规则即可精确命中该客户端 wsi。

小结

lws_fi 提供了一条从"构建期开启 → 创建期挂规则 → 运行时按策略触发"的完整故障注入链路:

  1. 构建期:以-DLWS_WITH_SYS_FAULT_INJECTION=ON编译 lws;关闭时所有 API 退化为常量,零开销。
  2. 规则准备:通过lws_fi_add()/lws_fi_deserialize()把lws_fi_t规则装入lws_fi_ctx_t,通常挂在lws_context_creation_info.fic上;对象创建时用lws_fi_import()接管,用lws_fi_inherit_copy()按vh=xxx/、ss=xxx/、wsi=xxx/命名空间向下分发。
  3. 触发查询:lws 私有代码用lws_fi(),用户代码用lws_fi_user_*_fi()系列公开 API;按LWSFI_ALWAYS / DETERMINISTIC / PROBABILISTIC / PATTERN / PATTERN_ALLOC / RANGE策略决策,概率决策由 xoshiro256 PRNG 支撑,种子可通过--fault-seed固定以便复现。
  4. 命令行接入:minimal 示例可通过--fault-injection "a,b,c"直接注入,(10%)、(....X.X)、(123..456)语法分别对应概率、位模式与范围取数。

配合内置的数十个知名故障点(context/vhost 创建失败、dnsfail、connfail、sendfail、udp_tx_loss、ss/sspc/ssproxy 系列),测试人员无需构造复杂的真实故障环境,即可在 CI 或本地一键复现原本低概率出现的错误路径,是验证 lws 应用健壮性的实用工具。

  • 人工智能
  • AI Agent
  • 多模态
  • 语音
  • AI 应用

【免费下载链接】ten-framework

Open-source framework for conversational voice AI agents

项目地址:https://gitcode.com/TEN-framework/ten-framework
点击查看免费下载

相关推荐

上一篇:jQuery 速查表:reference 项目中开发者高频 API 的快速参考指南
下一篇:高效掌握ControlNet-v1-1_fp16_safetensors:从问题诊断到实战优化的完整指南

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/29 5:41:53

使用 scenedetect 将切割好的视频进行正序倒序自循环

在数字视频处理的过程中,我们常常需要对现有的视频素材进行剪辑、倒序、拼接等操作,以便创作出更具创意和视觉冲击力的作品。无论是制作短视频、广告,还是进行自定义视频效果的设计,了解如何自动化地处理视频文件是非常有价值的。 本文将指导一步步学习如何使用 Python 和…

作者头像 李华
网站建设 2026/9/29 5:41:38

Hindsight机制:让Dify上的LLM应用在复盘循环中持续进化

1. Hindsight是什么&#xff1a;从英文热词到AI开发方法论1.1 这个词的本来面目和技术圈的两次翻红Hindsight这个英文单词的本义是"事后聪明"、"后见之明"&#xff0c;英文里还有句老话叫hindsight is 20/20&#xff0c;意思是"事后看谁都一清二楚&qu…

作者头像 李华
网站建设 2026/9/29 5:40:35

C语言宏定义实战:用TaoToken统一管理跨平台编译配置

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/29 5:38:56

软件工程过程模型选型指南:七种常见模型对比与避坑

做软件工程的人&#xff0c;几乎都会在某个阶段被“过程模型”四个字绊一下。刚入门时觉得它像管理学里的名词&#xff0c;工作几年后才发现&#xff0c;过程模型其实是一套风险分配方案&#xff1a;把需求、设计、编码、测试、交付这些活动&#xff0c;按不同节奏和顺序排布&a…

作者头像 李华
网站建设 2026/9/29 5:38:53

大麦网抢票脚本到底怎么买到票

大麦网抢票脚本到底怎么买到票 【免费下载链接】Automatic_ticket_purchase 大麦网抢票脚本 项目地址: https://gitcode.com/GitHub_Trending/au/Automatic_ticket_purchase 晚上八点开票&#xff0c;页面上"立即购买"按钮停留的时间只有几秒钟。这个大麦网抢…

作者头像 李华