
人工智能AI Agent多模态语音AI 应用【免费下载链接】ten-frameworkOpen-source framework for conversational voice AI agents项目地址https://gitcode.com/TEN-framework/ten-framework点击查看免费下载本篇文章基于仓库中 libwebsockets 的 minimal-raw-netcat 示例 展开完整讲解如何借助 libwebsocketslws的 raw 模式把一个外来的 TCP 客户端套接字和 stdin 文件描述符同时收养进 lws 事件循环实现stdin → 远程服务器 → stdout的双向数据搬运。读完本文你不仅能独立编译、运行和调参这个netcat 变体还能从源码层面理解LWS_CALLBACK_RAW_*回调族、lws_adopt_descriptor_vhost()收养机制以及定时器在连接收尾阶段的作用为自行编写基于 lws raw API 的转发器、代理或串口工具打下基础。示例定位libwebsockets raw 家族中的网络猫minimal-raw-netcat 是 lws 官方 minimal-examples 中 raw 系列示例 的一员。raw 模式是 libwebsockets 区别于纯 WebSocket 能力的重要扩展它允许 lws 事件循环管理非 HTTP/WS 语义的描述符包括普通 TCP/UDP 套接字、文件、设备节点、FIFO 甚至串口。在 raw 示例总览表 中各示例的分工如下示例演示内容minimal-raw-adopt-tcp收养别人已连接的 TCP 套接字minimal-raw-adopt-udp创建 UDP 套接字并读写minimal-raw-fallback-httpHTTP(S) 服务回退到指定角色与协议minimal-raw-file将文件描述符设备节点、FIFO、普通文件等收养进事件循环minimal-raw-netcat把 stdin 写到远程服务器并把返回内容打印到 stdoutminimal-raw-proxy / -fallback监听并代理到指定 IP/端口可以看到minimal-raw-netcat 的独特之处在于它同时收养了两类描述符一个由程序自己创建并 connect 好的外来TCP 套接字对应远程服务器文件描述符 0即 stdin标准输入。这正是LWS_CALLBACK_RAW_*回调族中文件描述符与套接字描述符两套回调在同一次运行中同时被触发的经典样例。编译CMake 构建与前置条件示例的构建方式与其 README 描述一致cmake . make工程配置见 CMakeLists.txt其中有几个值得注意的约束find_package(libwebsockets CONFIG REQUIRED)要求系统已安装并导出了 libwebsockets 的 CMake 配置require_lws_config(LWS_WITH_SERVER 1 requirements)示例编译前会强制校验 lws 编译时开启了LWS_WITH_SERVER宏。虽然本例并没有监听端口但它依赖服务端相关的 vhost / adoption 基础设施链接阶段根据websockets_shared变量选择共享库websockets_shared或静态库websockets。在本仓库中libwebsockets 以 third_party/libwebsockets 的形式完整内置含BUILD.gn与output_libs.gni因此也可以把它视为 TEN-framework 构建体系中的一个第三方依赖来交叉编译、复用其产物。用法与命令行参数程序的命令行接口由源码通过lws_cmdline_option()解析见 minimal-raw-netcat.c启动时打印的提示信息为LWS minimal raw netcat [--server ip] [--port port] [-w ms]支持的参数及语义如下参数作用默认值源码位置--server ip目标服务器地址IP 或域名libwebsockets.orgL193-L194--port port目标端口字符串形式80L190-L191-w msstdin 关闭后、关闭远端套接字前的等待毫秒数100见下文说明L196-L197-d N设置 lws 日志级别数字LLL_USER \| LLL_ERR \| LLL_WARN \| LLL_NOTICEL152-L153关于-w有一个值得注意的细节README 文字描述为stdin 关闭后等待 1 秒再输出在途结果但源码 L38 中us_wait_after_input_close的默认值是LWS_USEC_PER_SEC / 10即100 毫秒LWS_USEC_PER_SEC为 1 秒的微秒数 1000000除以 10 得 100000 微秒。传入-w时则按1000 * atoi(p)微秒计算即单位为毫秒。也就是说实际默认等待时间以源码为准可通过-w 1000显式调整为 README 描述的 1 秒。日志全部输出到stderr因此可以用2log之类的方式把日志与业务输出stdout 上的远端响应分离。运行演示与输出逐行解读README 给出的典型调用是用echo拼一个 HTTP/1.1 请求喂给 stdin观察程序把请求转发给远程服务器并打印响应echo -e -n GET / http/1.1\r\n\r\n | ./lws-minimal-raw-netcat运行输出节选自原 README时间戳为历史数据[2018/05/02 08:53:53:2665] USER: LWS minimal raw netcat [--server ip] [--port port] [2018/05/02 08:53:53:2667] NOTICE: Creating Vhost default (no listener), 1 protocols, IPv6 off [2018/05/02 08:53:53:2703] USER: Starting connect... [2018/05/02 08:53:53:5644] USER: Connected to libwebsockets.org:80... [2018/05/02 08:53:53:5645] USER: LWS_CALLBACK_RAW_ADOPT [2018/05/02 08:53:53:5645] USER: LWS_CALLBACK_RAW_ADOPT_FILE [2018/05/02 08:53:53:5646] USER: LWS_CALLBACK_RAW_RX_FILE [2018/05/02 08:53:53:5646] USER: LWS_CALLBACK_RAW_CLOSE_FILE [2018/05/02 08:53:53:8600] USER: LWS_CALLBACK_RAW_RX (186) HTTP/1.1 301 Redirect server: lwsws Strict-Transport-Security: max-age15768000 ; includeSubDomains location: https://libwebsockets.org content-type: text/html content-length: 0这段输出本身就是一个回调时序图可以这样理解Vhost 创建日志显示Creating Vhost default (no listener), 1 protocols——程序创建了不带监听端口的 vhost见下文上下文与 vhost并注册了 1 个协议raw-test外部连接建立Starting connect...→Connected to libwebsockets.org:80...对应源码中手工socket()connect()的过程套接字被收养LWS_CALLBACK_RAW_ADOPT对应lws_adopt_descriptor_vhost(..., LWS_ADOPT_SOCKET, ...)stdin 被收养并读到 EOFLWS_CALLBACK_RAW_ADOPT_FILE→LWS_CALLBACK_RAW_RX_FILE→LWS_CALLBACK_RAW_CLOSE_FILE对应lws_adopt_descriptor_vhost(..., LWS_ADOPT_RAW_FILE_DESC, ...)收养 fd 0随后管道因echo写完而 EOF触发关闭回调远端响应回灌LWS_CALLBACK_RAW_RX (186)表示收到 186 字节随后逐字节putchar到 stdout即上文的 HTTP 响应头。README 同时提醒示例什么都自己做。演示中远端服务器在空闲约 5 秒后主动关闭连接触发LWS_CALLBACK_RAW_CLOSE此后程序会继续运行直到你按下^CSIGINT。源码级原理拆解全局状态与协议注册源码 L34-L38 定义了核心全局状态static struct lws *raw_wsi, *stdin_wsi; /* 远端套接字与 stdin 各自的 wsi */ static uint8_t buf[LWS_PRE 4096]; /* 转发缓冲区预留 LWS_PRE 头空间 */ static int waiting, interrupted; static struct lws_context *context; static int us_wait_after_input_close LWS_USEC_PER_SEC / 10;buf预留LWS_PRE字节是 lws 的安全要求lws_write()需要协议头部空间直接复用缓冲区时必须在数据前留白waiting记录本次从 stdin 读到的字节数供写回调使用回调函数统一挂在协议raw-test上L130-L133并通过LWS_PROTOCOL_LIST_TERM终止协议表。回调族两类描述符、两套生命周期回调函数callback_raw_test()L40-L128按lws_callback_reasons分发。对应的事件常量定义在 lws-callbacks.h回调枚举值触发时机本例处理LWS_CALLBACK_RAW_ADOPT62套接字被收养进事件循环打印日志并请求可写lws_callback_on_writableLWS_CALLBACK_RAW_CLOSE60远端套接字关闭置interrupted 1lws_cancel_service()唤醒事件循环退出LWS_CALLBACK_RAW_RX59套接字收到数据逐字节putchar并fflush(stdout)LWS_CALLBACK_RAW_WRITEABLE61套接字可写恢复 stdin 流控用lws_write(..., LWS_WRITE_RAW)写出waiting字节LWS_CALLBACK_RAW_ADOPT_FILE63文件描述符被收养打印日志LWS_CALLBACK_RAW_RX_FILE64文件描述符可读read(0, buf, sizeof(buf))读 stdin请求远端可写并暂停 stdin 流控LWS_CALLBACK_RAW_CLOSE_FILE66文件描述符 EOF/关闭置空stdin_wsi若远端仍在则用lws_set_timer_usecs()启动收尾定时器LWS_CALLBACK_TIMER—定时器到期置interruptedlws_cancel_service()结束程序其中LWS_CALLBACK_RAW_RX_FILE中lws_rx_flow_control(wsi, 0)与LWS_CALLBACK_RAW_WRITEABLE中lws_rx_flow_control(stdin_wsi, 1)构成一对背压控制stdin 数据被读走但远端尚未写完成时暂停继续读取避免缓冲区堆积。上下文与 vhost不监听也能运行主函数中先以LWS_SERVER_OPTION_EXPLICIT_VHOSTS创建 context再单独创建 vhostL158-L174info.options LWS_SERVER_OPTION_EXPLICIT_VHOSTS; context lws_create_context(info); info.port CONTEXT_PORT_NO_LISTEN_SERVER; /* 明确表示不创建监听套接字 */ info.protocols protocols; vhost lws_create_vhost(context, info);CONTEXT_PORT_NO_LISTEN_SERVER让 vhost 只承载协议与回调分发、不监听任何端口这与 raw 模式只做描述符管理的定位完全吻合。外部套接字手工 connect 再交给 lws与通常的lws_client_connect_via_info()不同本示例刻意手工完成域名解析与连接以演示外来套接字的收养路径L185-L228getaddrinfo(server, port, ...)解析目标AF_UNSPEC允许 IPv4/IPv6遍历结果用socket()创建SOCK_STREAM套接字connect()到首个可用的地址成功后调用收养 APIraw_wsi lws_adopt_descriptor_vhost(vhost, LWS_ADOPT_SOCKET, sock, protocols[0].name, NULL);lws_adopt_descriptor_vhost()的原型与语义见 lws-adopt.h成功时返回绑定该描述符的新 wsi失败时关闭描述符并返回 NULL。收养类型枚举lws-adopt.h L66-L75中LWS_ADOPT_RAW_FILE_DESC 0按原始文件描述符收养LWS_ADOPT_SOCKET 2按套接字收养缺省即文件另有LWS_ADOPT_ALLOW_SSL、LWS_ADOPT_FLAG_UDP、LWS_ADOPT_RAW_SOCKET_UDP等组合。stdin 的收养与事件循环随后用同样的 API、以LWS_ADOPT_RAW_FILE_DESC把 fd 0stdin也收养进来L239-L245sock.filefd 0; stdin_wsi lws_adopt_descriptor_vhost(vhost, LWS_ADOPT_RAW_FILE_DESC, sock, protocols[0].name, NULL);此后两个描述符完全纳入 lws 的poll事件循环while (n 0 !interrupted) n lws_service(context, 0);lws_service()驱动回调分发interrupted可由 SIGINTsigint_handler、远端关闭LWS_CALLBACK_RAW_CLOSE或收尾定时器LWS_CALLBACK_TIMER置位从而优雅退出。lws_cancel_service()用于从回调内部唤醒阻塞中的事件循环。收尾时序为什么它比真 netcat 更耐心这是示例 README 着重强调的优势stdin 关闭后不立即断开而是等待在途数据返回。stdin EOF 触发LWS_CALLBACK_RAW_CLOSE_FILE若远端 wsi 仍存活调用lws_set_timer_usecs(raw_wsi, us_wait_after_input_close)注册一次性定时器定时器到期触发LWS_CALLBACK_TIMER置interrupted并取消服务进程退出。因此请求发出后即使 stdin 已经关闭远端尚未到达的响应仍能在等待窗口内通过LWS_CALLBACK_RAW_RX打印到 stdout——这正是演示输出中LWS_CALLBACK_RAW_CLOSE_FILE之后仍能看到LWS_CALLBACK_RAW_RX (186)的原因。等待时长由-w毫秒参数控制。扩展思路把示例改造成通用双向管道结合源码结构minimal-raw-netcat 可以直接演化为多种实用工具改动点都很小本机 HTTP 探测./lws-minimal-raw-netcat --server 127.0.0.1 --port 8080配合echo或脚本向本地服务发送原始请求绕过curl的规范化回显/延时测量连接任意 echo 服务观察往返数据串口/FIFO 适配参照同目录的 minimal-raw-file 与 minimal-raw-serial 示例把 stdin 换成设备节点即可把文件描述符收养推广到串口数据搬运双向代理雏形若要同时转发远端到本地的数据而不只是打印只需在LWS_CALLBACK_RAW_RX中把收到的字节写回 stdin 对应的 wsiLWS_WRITE_RAW即向 minimal-raw-proxy 看齐。从 raw/README.md 总览 可见adopt-tcp、adopt-udp、proxy 等示例分别覆盖了收养既有连接UDP 读写监听代理等相邻场景可与本示例对照阅读形成对 lws raw 能力面的完整认识。注意事项与限制外部依赖与网络可达性示例默认连接libwebsockets.org:80属于互联网外部站点实际复现时可能因网络策略不可达建议先用--server 127.0.0.1 --port 本地端口指向本地服务验证构建前提需要系统预装带 CMake 配置导出的 libwebsockets且库编译时开启LWS_WITH_SERVER本仓库内置的 third_party/libwebsockets 可作为替代构建来源默认等待时长README 描述等待 1 秒源码默认实为 100 msLWS_USEC_PER_SEC / 10需要 1 秒请显式传-w 1000单连接模型示例面向单条连接且 stdin 关闭即进入收尾流程不适合需要持续交互或并发多路转发的场景缓冲区大小转发缓冲区为LWS_PRE 4096字节超过 4 KB 的单次读入会分多次写出符合流式处理预期但高吞吐场景可相应调大。总体而言minimal-raw-netcat 是理解 libwebsockets raw 模式最直接的入门样例它把外来套接字收养文件描述符收养raw 回调族定时器收尾四条主线压缩在约 260 行 C 代码中既有完整的端到端可运行性又为后续基于 lws 编写代理、串口工具和自定义协议转发器提供了可复用的骨架。赞分享人工智能AI Agent多模态语音AI 应用【免费下载链接】ten-frameworkOpen-source framework for conversational voice AI agents项目地址https://gitcode.com/TEN-framework/ten-framework点击查看免费下载相关推荐Monolog SocketHandler 实战指南用 PHP 套接字把日志实时送往远端日志服务器Monolog SocketHandler 实战指南用 PHP 套接字把日志实时送往远端日志服务器 导读 Monolog 是 Laravel 等 PHP 框架示例工程数据库教程后端基于 libwebsockets 的最小化 HTTPS 服务器minimal-http-server-tls 实战与源码解析基于 libwebsockets 的最小化 HTTPS 服务器minimal http server tls 实战与源码解析 本指南以 TEN framewo人工智能AI Agent多模态语音AI 应用OpenChamber Dev Server Tunnel 深度解析原始字节级远程开发服务器隧道协议与实现OpenChamber Dev Server Tunnel 深度解析原始字节级远程开发服务器隧道协议与实现 本篇技术指南聚焦 OpenChamber 桌面端的AI Agent人工智能代码智能体交互助手上一篇解放双手中文字幕自动下载神器ChineseSubFinder深度解析 下一篇fastbook机器人学智能机器人控制算法终极指南创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考