arduino-cli gRPC 客户端实战:用 client_example 打通 daemon 服务与代理链路

发布时间:2026/10/5 2:19:23
arduino-cli gRPC 客户端实战:用 client_example 打通 daemon 服务与代理链路 开发工具嵌入式【免费下载链接】arduino-cliArduino command line tool项目地址https://gitcode.com/gh_mirrors/ar/arduino-cli点击查看免费下载client_example是 arduino-cli 仓库中一个专门模拟 gRPC 消费者的示例客户端其完整源码位于 rpc/internal/client_example含main.go、squid.conf与一个测试用 sketch。本文以 rpc/internal/client_example/README.md 为骨架逐步讲解如何启动arduino-cli daemon、运行客户端走通从版本查询到平台/库管理的完整调用链并通过 Docker Squid 代理验证 arduino-cli 的network.proxy配置是否真正生效。读完本文你将能够独立搭建一套gRPC 服务端 外部客户端 本地代理的联调环境并理解 arduino-cli 的核心 RPC 接口形态。一、client_example 是什么按照 README 的定位这是一个模拟 gRPC 消费者的客户端程序。arduino-cli 的 gRPC 接口文档相对零散官方暂时用它来记录与 gRPC 接口的交互方式——也就是说main.go中每一次 RPC 调用都是对 daemon 模式下 arduino-cli 对外 API 的活文档。整个目录结构如下rpc/internal/client_example/main.go客户端主程序演示数十个 RPC 方法的标准调用方式rpc/internal/client_example/squid.conf用于代理验证实验的 Squid 配置文件rpc/internal/client_example/hello/hello.ino一个仅含空setup()/loop()的最小测试 sketch供LoadSketch、Compile等接口使用。服务端的 RPC 方法清单在 rpc/cc/arduino/cli/commands/v1/commands.proto 中统一定义Create、Init、UpdateIndex、PlatformInstall、Compile、Upload、LibraryInstall、Monitor、Debug、SettingsGetValue/SettingsSetValue等全部通过ArduinoCoreService服务暴露。二、快速开始daemon 与客户端的组合运行README 给出的使用方式非常简洁只有两步arduino-cli daemon client_example第一步启动 arduino-cli 的 gRPC 服务端第二步运行示例客户端二者默认在localhost:50051上建立连接。从源码看客户端连接逻辑在 rpc/internal/client_example/main.go#L44-L50conn, err : grpc.NewClient(localhost:50051, grpc.WithTransportCredentials(insecure.NewCredentials())) if err ! nil { log.Fatal(error connecting to arduino-cli rpc server, you can start it by running arduino-cli daemon) }需要说明两点前提连接为明文传输示例使用grpc.WithTransportCredentials(insecure.NewCredentials())不启用 TLS因此只适合本机联调默认端口来自配置50051是daemon.port的默认值定义在 internal/cli/configuration/defaults.godaemon 命令实际监听地址在 internal/cli/daemon/daemon.go 中被固定为127.0.0.1。daemon 命令的可调参数结合 internal/cli/daemon/daemon.goarduino-cli daemon支持以下参数参数默认值说明--port配置项daemon.port默认 50051daemon 监听的 TCP 端口传0时由操作系统随机分配并回显实际端口--daemonizefalse为true时父进程结束后 daemon 不随之退出--debugfalse启用 gRPC 调用的调试日志--debug-file空将调试日志追加写入指定文件必须与--debug同时使用--debug-filter[]只显示指定的 gRPC 调用--max-grpc-recv-message-size16 MiBdaemon 可接收的最大消息字节数必须 1024服务端启动后会打印监听地址与端口daemonResult随后阻塞在s.Serve(lis)上等待客户端连接。三、客户端完整调用链逐段拆解main.go的main()函数把一次典型的 Arduino 工作流串成了顺序调用。理解这条调用链就等于掌握了 arduino-cli gRPC API 的使用顺序其中几个关键阶段尤其值得注意。3.1 无状态接口先行Version 与 LoadSketch客户端最先调用Version与LoadSketch注释明确说明它们不需要任何 setup 或 init 流程rpc/internal/client_example/main.go#L67-L72。callVersion直接请求服务端版本号callLoadSketch则读取hello目录的 sketch 信息返回主文件、位置、其他 sketch 文件与附加文件列表。3.2 用 Settings 接口隔离测试环境为不污染现有 arduino-cli 安装客户端通过os.MkdirTemp创建临时目录作为数据目录再通过SettingsSetValue写入三个关键路径rpc/internal/client_example/main.go#L74-L77callSetValue(client, directories.data, dataDir) callSetValue(client, directories.downloads, path.Join(dataDir, staging)) callSetValue(client, directories.user, path.Join(dataDir, sketchbook))这里体现出SettingsSetValueRequest的设计要点EncodedValue是JSON 编码的字符串所以路径要加引号、数组要用方括号。随后示例演示了修改-保存-回读-再保存的完整流程callConfigurationSave以 JSON 格式输出当前全部配置对应 proto 中的ConfigurationSaveRequestsettings_format允许json或yaml见 rpc/cc/arduino/cli/commands/v1/settings.proto一次SetValue修改daemon.port为422、board_manager.additional_urls为数组[ https://example.com ]再次保存用SettingsGetValue回读daemon.port与directories.data将daemon.port置空后再次保存。3.3 实例生命周期Create → Init → 后续操作Create返回一个Instance此后所有需要上下文的 RPC 都要携带这个实例 ID。Init是服务端流式接口客户端必须循环Recv()直到io.EOF期间解析两种消息rpc/internal/client_example/main.go#L301-L333GetDownloadProgress()索引文件下载进度GetTaskProgress()初始化任务阶段。3.4 平台管理更新索引、搜索、安装、升级、卸载UpdateIndex同样是流式接口客户端循环消费下载进度直到 EOF。值得注意的细节是索引更新后不会被隐式检测必须再次调用Init才能加载新索引——示例在UpdateIndex之后显式追加了一次Initrpc/internal/client_example/main.go#L116-L119。平台管理调用的完整序列为PlatformSearch(samd)搜索平台打印id与latest versionPlatformInstall(arduino:samd1.6.19)安装指定版本消费下载进度与任务进度PlatformUpgrade(arduino:samd)升级到最新版BoardDetails(arduino:samd:mkr1000)查询板卡详情工具依赖、配置选项BoardSearch()全量搜索板卡最后PlatformUninstall(arduino:samd)卸载平台。安装/升级/卸载的实现模式一致发起流式请求 → 循环Recv()→ 遇io.EOF结束 → 期间按消息类型打印DownloadProgress或TaskProgress。这是 arduino-cli 所有长耗时操作的标准消费模式可直接复用到自己的客户端中。3.5 编译与上传Compile请求携带Fqbn如arduino:samd:mkr1000、SketchPathhello目录与Verbose: true响应流中的OutStream/ErrStream分别对应编译过程的 stdout 与 stderrrpc/internal/client_example/main.go#L494-L531。Upload被注释掉原因是必须有真实板卡连接。若取消注释需要填充Port结构Address如/dev/ttyACM0与Protocol如serial。同样被注释的还有Debug流程——它使用双向流式接口Debug(stream DebugRequest) returns (stream DebugResponse)示例中向调试器发送info registers与quit命令并等待(gdb)提示符。3.6 板卡枚举与热插拔监听BoardListAll列出所有已安装平台提供的板卡示例用mkr过滤BoardList列出当前连接的板卡与匹配结果BoardListWatch服务端流式长连接监听板卡接入/移除事件。示例中事件类型取add/remove/error客户端在 goroutine 中消费事件流主协程用 10 秒定时器控制观察时长后退出rpc/internal/client_example/main.go#L601-L635。3.7 库管理下载、安装、升级、搜索、依赖解析、卸载库相关调用集中在WiFi101、Arduino_MKRIoTCarrier、ArduinoIoTCloud等真实库上流程如下UpdateLibrariesIndex更新库索引之后再次InitLibraryDownload(WiFi1010.15.2)仅下载到 staging 目录LibraryInstall(WiFi1010.15.1)安装指定版本随后以0.15.2再装一次完成版本替换LibraryInstall(Arduino_MKRIoTCarrier0.9.9)时设置NoDeps: true跳过依赖安装LibraryUpgradeAll升级全部已安装库LibrarySearch(audio)搜索库LibraryResolveDependencies(ArduinoIoTCloud)打印依赖名、要求版本与已安装版本LibraryList列出已安装库All: false、Updatable: falseLibraryUninstall(WiFi101)卸载。四、代理链路验证Docker Squid 实验README 用一组 Docker 命令演示如何在本地起一个 Squid 代理并确认 arduino-cli 的网络请求确实穿过代理。4.1 启动 Squid 容器docker run --name squid -d --restartalways \ --publish 3128:3128 \ --volume /path/to/squid.conf:/etc/squid/squid.conf \ --volume /srv/docker/squid/cache:/var/spool/squid \ sameersbn/squid:3.5.27-2其中squid.conf文件就在本目录rpc/internal/client_example/squid.conf启动时把卷路径指向它即可。该配置的关键规则包括http_port 3128监听端口与--publish 3128:3128对应acl SSL_ports port 443http_access deny CONNECT !SSL_ports仅允许对 443 端口的CONNECT隧道HTTPS 代理http_access allow localnet/allow localhost/allow all放行本地与局域网流量。4.2 实时观察代理日志docker exec -it squid tail -f /var/log/squid/access.log如果代理生效日志中会出现类似下面的记录——TCP_TUNNEL/200表示 arduino-cli 通过本地代理以隧道方式连接downloads.arduino.cc:443下载索引1612176447.893 400234 172.17.0.1 TCP_TUNNEL/200 116430 CONNECT downloads.arduino.cc:443 - HIER_DIRECT/104.18.28.45 - 1612176448.197 400245 172.17.0.1 TCP_TUNNEL/200 1621708 CONNECT downloads.arduino.cc:443 - HIER_DIRECT/104.18.28.45 - 1612176448.946 400256 172.17.0.1 TCP_TUNNEL/200 354882 CONNECT downloads.arduino.cc:443 - HIER_DIRECT/104.18.28.45 -日志字段依次为时间戳、请求耗时毫秒、来源 IP、隧道状态码、传输字节数、CONNECT 目标域名:443、以及实际出口方式。4.3 客户端如何配置代理main.go中callSetProxy通过设置项把代理写入配置rpc/internal/client_example/main.go#L244-L254client.SettingsSetValue(context.Background(), rpc.SettingsSetValueRequest{ Key: network.proxy, EncodedValue: http://localhost:3128, })客户端在主流程中先setProxy、再执行两次UpdateIndex——这正是为了用索引下载来验证代理配置已生效。在squid.conf与代理已就绪的前提下两次索引更新对应的 CONNECT 请求会连续出现在 access.log 中。从底层实现看network.proxy并非示例专属它由 internal/cli/configuration/network.go 的NetworkProxy()解析为*url.URL随后在NewHttpClient()与DownloaderConfig()中通过http.ProxyURL(proxy)注入 HTTP 传输层索引下载走的是 downloader 配置因此设置代理后重启 daemon 即可让所有下载类 RPC 走代理。示例客户端因为是临时进程、每次启动重新SettingsSetValue所以无需重启即可生效。五、常见疑问与排查要点连接失败怎么办确认 daemon 正在运行客户端log.Fatal会提示先执行arduino-cli daemon并检查端口是否被占用——daemon 启动时若端口被占会报 Address already in useinternal/cli/daemon/daemon.go为什么有些调用没有输出BoardListWatch观察 10 秒后自动退出Upload/Debug需要真实硬件默认被注释为什么代理日志看不到流量检查容器内/etc/squid/squid.conf是否为仓库提供的配置、3128端口映射是否成功以及network.proxy的 JSON 值是否带引号临时目录的生命周期客户端用defer os.RemoveAll(dataDir)在退出时清理临时数据目录因此每次运行都是全新环境可重复执行验证。六、延伸阅读RPC 服务与消息定义rpc/cc/arduino/cli/commands/v1/commands.proto、rpc/cc/arduino/cli/commands/v1/settings.protodaemon 服务端实现internal/cli/daemon/daemon.go网络代理与 HTTP 客户端实现internal/cli/configuration/network.go其他语言的调用方式可参考 rpc/internal/get_version_example 与 rpc/internal/client_example/hello/hello.ino 所在目录中的其他示例。简而言之client_example是理解 arduino-cli gRPC 接口的最佳起点——先arduino-cli daemon再跑client_example即可观察一整套真实调用配合 Docker Squid 与network.proxy设置还能顺带验证网络链路的代理行为。赞分享开发工具嵌入式【免费下载链接】arduino-cliArduino command line tool项目地址https://gitcode.com/gh_mirrors/ar/arduino-cli点击查看免费下载相关推荐从零开始使用samvit_huge_patch16.sa1b5分钟上手图像特征提取从零开始使用samvit_huge_patch16.sa1b5分钟上手图像特征提取 想要快速掌握 图像特征提取 的终极工具吗samvit_huge_patctonic-build 代码生成实战从 build.rs 到 gRPC 客户端与服务端tonic build 代码生成实战从 build.rs 到 gRPC 客户端与服务端 本篇技术指南以 tonic build/README.md https后端RPC框架FlatBuffers 与 gRPC 的 TypeScript 实践跑通 greeter 服务端与客户端FlatBuffers 与 gRPC 的 TypeScript 实践跑通 greeter 服务端与客户端 FlatBuffers 是一种零拷贝、内存高效的序列序列化跨平台编译器上一篇OpCore-Simplify15分钟搞定黑苹果EFI配置的智能助手下一篇OpenRAM开源SRAM编译器5步掌握专业级内存生成技术创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考