新闻详情

新闻详情

首页 / 资讯中心 / 详情

Flutter迁移OpenHarmony:mDNS局域网设备发现实战与坑点解析

发布时间:2026/9/9 16:08:52来源:尧图网络
Flutter迁移OpenHarmony:mDNS局域网设备发现实战与坑点解析
最近手头有个 Flutter 项目要往 OpenHarmony 上迁移碰到一个很有意思的问题App 需要在局域网里自动发现智能设备不能让人手动输 IP。原应用在 Android 上用的是 multicast_dns 这个包一切正常但换到鸿蒙环境后问题就来了——收到的服务列表时有时无甚至直接空转。这就逼着我把整个 mDNS 方案重新捋了一遍从协议原理、multicast_dns 的用法一直折腾到鸿蒙原生侧的能力接入。这篇文章就当是把这个过程完整记录下来给同样在做 Flutter for OpenHarmony 设备发现需求的同学一个参考。文章主要涉及三块零配置网络里 mDNS/Bonjour/Zeroconf 到底是什么关系multicast_dns 在 Flutter 里的标准用法以及如何在 OpenHarmony 上做适配、跨设备跑通“发现-连接”的完整流程。适合正在做局域网 SDK、智能家居 App、多屏协同或者设备调试工具并且有把 Flutter 应用跑到鸿蒙上的需求的人。1. 零配置网络到底在解决什么问题先说个场景。你做了一台带 WiFi 模块的小设备用户通过手机 App 去控制它。设备连上路由器后如果路由器开了 DHCP它会拿到一个随机分配的 IP比如 192.168.1.37。那 App 怎么知道这个 IP传统做法是让用户进路由器后台查或者在设备上装个显示屏显示 IP再手动打到 App 里。这体验显然不行。更合理的方式是App 在局域网里喊一嗓子“谁是设备”设备听到后回应“我是设备IP 是 xxx端口是 yyy”。整个过程不需要用户输入任何网络信息也不需要提前配置 DNS 服务这就是零配置网络Zeroconf的核心价值。Zeroconf 本身并不是单一协议它实际上解决了三件事自动分配 IP 地址当网络中没有 DHCP 服务器时设备自己从 169.254.0.0/16 段挑一个地址完成链路本地寻址。名称解析把设备名映射成 IP常见实现就是 mDNS。服务发现找到网络上提供特定类型服务的实例常见实现是 DNS-SD。在苹果生态里Bonjour 就是这一整套能力的实现。大家经常听到的 Bonjour、Zeroconf、mDNS、DNS-SD其实经常被混着说但它们之间的逻辑关系需要先理清。1.1 没有服务发现时开发者的痛拿我自己之前做的一个调试工具举例需要扫描局域网内的硬件开发板。最初版本让用户手动输入板子 IP开始测试没问题。后来设备数量增多、网络环境复杂化每天都有同事问“为什么昨天能用、今天连不上了”。查来查去基本都是 DHCP 分配的 IP 变了或者设备启动时网络没就绪导致 IP 位序变化。后来换了 mDNS 方案设备启动后自动注册一个_debug._tcp服务App 启动后打开监听几十毫秒就能发现全部设备。这个过程最大的收益不是省掉了输入 IP 这一步而是让整个系统架构发生了质变App 不再关心设备的网络地址设备也不再依赖固定的拓扑结构。你可以在同一个局域网里增加一台设备App 下次打开就自动看到了完全不用手工配置。这个思路在智能家居里特别常见。一台灯、一个音箱、一个投影仪它们都会注册类似_led._tcp、_speaker._tcp的服务。App 只需要知道服务类型就能找到所有对应设备然后进一步解析出设备 IP、端口、设备能力等信息。1.2 mDNS、Bonjour、Zeroconf 的关系很多人包括我以前也容易混。这里用一个表格直接梳理术语全称/来源定位典型实现ZeroconfZero Configuration Networking一整套零配置组网思想不是一个具体软件mDNSMulticast DNS域名解析协议在局域网内通过组播解析.local主机名Apple Bonjour、AvahiDNS-SDDNS Service Discovery基于 DNS 记录实现服务发现的一组机制Apple Bonjour、Android NSDBonjourApple 公司的实现苹果对 Zeroconf/mDNS/DNS-SD 的商业实现和统称macOS、iOS 内置从实现角度看mDNS 解决的是“根据名字找 IP”DNS-SD 解决的是“根据服务类型找服务实例”。在实际代码里multicast_dns 这个包通常同时完成两件事浏览服务时发的是 DNS-SD 的 PTR 查询拿到实例后解析 SRV/TXT/A 记录时又是 mDNS 的解析逻辑。2. mDNS 和 DNS-SD 的工作原理从包结构说起mDNS 在设计上其实是把普通 DNS 协议照搬到了局域网组播环境。它对 IP 层和 UDP 层做了个固定约定IPv4 组播地址是 224.0.0.251IPv6 组播地址是 ff02::fb端口固定是 5353。所有 mDNS 报文都发到这个组播地址同一链路上的设备只要加入了组播组就能收到。为什么不用普通的 UDP 广播广播虽然也能在二层局域网内传播但广播报文会被所有主机接收包括那些根本不关心服务发现的主机白白消耗 CPU。组播则只有加入特定组播组的主机才会处理报文效率更高也更容易扩展。2.1 一个 DNS-SD 查询过程全拆解假设我们想发现局域网里所有 HTTP 服务。HTTP 服务的 DNS-SD 类型名是_http._tcp.local。客户端发出一条 PTR 查询问_http._tcp.local的 PTR 记录有哪些。如果局域网里有一台设备的 Web 服务想被找到它启动时会往组播组发送一条响应内容大致如下记录类型记录名内容作用PTR_http._tcp.localMyWebServer._http._tcp.local列出服务实例SRVMyWebServer._http._tcp.local0 0 8080 myserver.local.服务所在主机名和端口A/AAAAmyserver.local.192.168.1.88主机 IP 地址TXTMyWebServer._http._tcp.localpath/index服务的附加属性客户端收到 PTR 响应后知道了服务实例的名字就会继续发 SRV 和 TXT 查询。SRV 告诉你主机名和端口然后通过 A/AAAA 记录拿到 IP。TXT 里可以携带一些自定义键值比如设备的型号、固件版本、支持的指令集等。从这个流程可以看到一次“发现服务”并不是简单的请求-响应而是一系列记录类型层层递进的过程。这也是为什么在网络环境不好时可能会发现服务名字、但拿不到 IP 或端口表现为“能看到设备但连不上”。2.2 TTL、缓存和重复抑制mDNS 协议为了保证局域网内信息一致性设计了几条比较有意思的规则这些规则在实际排查问题时会直接影响你的观察结果每一条记录都有 TTL设备退出网络时应该主动发送 TTL0 的响应来通知其他设备删除缓存。如果设备异常断电其他设备只能等 TTL 超时后自然清理。设备收到重复的响应报文时会做重复抑制duplicate suppression停止继续转发相同的响应避免组播风暴。记录不是单播推给某个请求方的而是共享给整条链路的所有设备类似于“给全小区的公告栏贴通知”。这些机制带来的实际体验是你第一次打开 App 查询服务可能要等几百毫秒甚至一秒但第二次再查因为设备端缓存了记录响应会快得多。如果网络里有些设备频繁上下线它残留的缓存条目可能会让你在 App 里看到“过期”设备这种假象给问题排查增加了不少难度。3. Flutter 里用 multicast_dns标准 API 和易踩的坑multicast_dns 是 pub.dev 上的一个纯 Dart 包底层没有依赖 Android/iOS 原生代码而是直接基于 dart:io 的 RawDatagramSocket 发送和接收组播报文。这个设计对跨平台迁移非常友好因为 Flutter for OpenHarmony 对 dart:io 的基础能力支持得已经比较成熟所以在“能否用”这个问题上理论上不会出现 MissingPluginException 这类问题。但“理论”和“实际”总是有差距。我先说一下它在标准 Flutter 环境里的用法然后再展开鸿蒙适配时的特殊点。3.1 最简 Demo发现局域网内所有 HTTP 服务在 pubspec.yaml 里引入依赖dependencies: multicast_dns: ^0.3.2创建发现管理器并启动扫描import package:multicast_dns/multicast_dns.dart; class MdnsBrowser { final MulticastDns _multicastDns MulticastDns.instance; void start() { _multicastDns.start(); _multicastDns.lookup(_http._tcp.local, onServiceFound: (service) { print(发现服务: ${service.name}); print( host: ${service.host}); print( port: ${service.port}); print( txt: ${service.txt}); }); } void stop() { _multicastDns.stop(); } }注意几个细节。lookup返回的是流需要监听如果你只是调用 lookup 而不 listen并不会持续接收结果。onServiceFound回调里的service.name是完整的实例名比如MyHTTP._http._tcp.local.带末尾的.local.点这是完整 DNS 域名格式别因为看到两个点就觉得异常。还有一个很多人会踩的坑MulticastDns.instance是单例。如果你在页面 A 里 start 了但没有 stop然后切到页面 B 又 start控制台经常会报Bad state: Stream has already been listened。这个异常一般不是你代码逻辑错了而是没有做好生命周期管理。规范做法是在 Widget 的dispose或页面的生命周期回调里调用stop。3.2 发布一个自己的服务multicast_dns 除了发现服务也支持发布服务。发布时需要指定服务实例名、类型、端口以及可选的 TXT 记录void register() { _multicastDns.registerService( name: DemoDevice, type: _flutter._tcp.local., port: 8080, txt: { role: led, version: 1.0.0, }, ); }发布之后同一局域网内其他 mDNS 客户端就可以通过查询_flutter._tcp.local找到这台设备。这里值得留意的是TXT 记录里所有值必须是字符串有些场景下你想传 int 或 bool需要先转成 String。发布服务还需要注意一个限制如果你发布的服务端口号服务端并没有真正监听客户端查到服务后去连接端口会直接连接失败。mDNS 本身不校验端口可用性所以发布服务前一定先起好对应的 socket 服务。Android 环境下还需要在 AndroidManifest.xml 里声明两个权限uses-permission android:nameandroid.permission.INTERNET / uses-permission android:nameandroid.permission.CHANGE_WIFI_MULTICAST_STATE /其中CHANGE_WIFI_MULTICAST_STATE很关键不声明它时WiFi 网卡默认会过滤掉非单播报文导致收不到任何组播响应这是很多人在真机上“扫不到设备”的第一原因。4. 真正适配 OpenHarmony纯 Dart 能用为什么还要做原生接入现在说重点OpenHarmony 上的适配问题。multicast_dns 本身是纯 Dart所以理论上只要flutter run -d ohos能启动应用它就能跑。我在 OpenHarmony 3.2 和 4.0 的工程里都试过确实可以启动不崩溃但实际运行的效果是多半情况下扫不到设备或只能扫到一部分。原因不是 Dart 代码的问题而是 OpenHarmony 的网络权限和组播行为约束和 Android 不太一样。主要体现在OpenHarmony 对网络访问权限管控更严格必须在module.json5里显式声明应用所需的网络权限。组播报文的收发与网络接口、防火墙规则、系统路由策略有关OpenHarmony 在这方面没有直接开放像 Android 那样宽松的 socket 组播开关。系统自带 mDNS 能力如果应用直接使用系统 API会比从 Dart 层发原始组播更稳定性能和缓存处理也更好。所以我的建议是不要只把 multicast_dns 当作唯一方案而是在鸿蒙上做一个轻量适配层优先走系统 mDNS 通道底层能力用 MethodChannel 暴露给 Flutter。这样既保留 Flutter 层 API 的统一性又能利用鸿蒙对 mDNS 的原生支持。4.1 先确认你的 Flutter 鸿蒙工程结构现在 Flutter for OpenHarmony 的工程结构和标准 Flutter 不太一样。在项目根目录下你会看到一个ohos目录这是 OpenHarmony 的工程目录。里面关键文件包括oh-package.json5鸿蒙侧依赖配置文件。entry/src/main/module.json5应用声明文件权限在这里配置。entry/src/main/ets/ArkTS 源码目录。要在鸿蒙工程里使用网络能力需要在module.json5的requestPermissions里加上网络权限{ module: { requestPermissions: [ { name: ohos.permission.INTERNET }, { name: ohos.permission.GET_WIFI_INFO } ] } }GET_WIFI_INFO并不是 mDNS 必须的但如果你的应用需要获取当前连接的 WiFi 信息来判断是不是在同一个局域网里最好也加上。注意权限列表里的 name 需要对比当前 SDK 的权限定义不同版本可能稍有差异。4.2 设计 MethodChannel 接口我为 Flutter 侧封装了一个MdnsChannel类所有能力都通过 MethodChannel 和 EventChannel 与鸿蒙原生通信。MethodChannel负责“命令”例如启动发现、停止发现、注册服务、注销服务。在 Flutter 侧static const MethodChannel _methodChannel MethodChannel(com.example.mdns/method); static const EventChannel _eventChannel EventChannel(com.example.mdns/events); Futurevoid startDiscovery(String type) async { await _methodChannel.invokeMethod(startDiscovery, {type: type}); } Futurevoid stopDiscovery(String type) async { await _methodChannel.invokeMethod(stopDiscovery); } Futurevoid registerService({ required String name, required String type, required int port, MapString, String txt const {}, }) async { await _methodChannel.invokeMethod(registerService, { name: name, type: type, port: port, txt: txt, }); }EventChannel负责持续推送“发现服务”的结果。因为服务发现是一个持续性的过程一个设备在发现周期内可能多次上线、更新、下线如果只在 MethodChannel 的返回结果里一次性返回就丢失了动态性。所以 EventChannel 更合适。StreamMdnsService get onServiceFound { return _eventChannel .receiveBroadcastStream() .map((event) MdnsService.fromMap(event as Mapdynamic, dynamic)); }设计接口时有一个很容易忽视的点type参数的格式。multicast_dns 里查询类型用的是_http._tcp.local有的实现接受末尾的.有的不接受。为了减少用户出错我统一在 Flutter 侧做了一次规范化无论传入_http._tcp.local还是_http._tcp.local.最终传给原生侧的都是不带末尾点的规范形式。4.3 鸿蒙原生侧实现 mDNS 发现在 OpenHarmony 的 ArkTS 侧系统提供了 mdns 相关的能力。不同 API 版本模块路径可能略有差异具体以你使用的 SDK 为准一般可以通过import { mdns } from kit.NetworkKit引用。一个简单的发现流程是创建指定服务类型的发现对象然后监听服务发现回调import { mdns } from kit.NetworkKit; let discovery: mdns.Discovery; function startDiscovery(type: string): void { discovery mdns.createDiscovery(type); discovery.on(discoverService, (service: mdns.DiscoveredServiceInfo) { console.info(发现服务: ${service.name}); }); discovery.startSearching(); }这里创造了一个createDiscovery和startSearching的调用形式不同 SDK 版本可能存在细节差异比如服务信息结构体字段名可能由name、host、port、txt组合而成也有可能是嵌套对象。在你集成时建议先打开 SDK 里的接口文档确认字段名。注册服务类似需要传入服务名称、服务类型、端口和 TXT 信息function registerService( name: string, type: string, port: number, txt: Recordstring, string ): void { const serviceInfo: mdns.RegisteredServiceInfo { name, type, port, txt, }; const registration mdns.createRegistration(serviceInfo); registration.start(); }鸿蒙侧实现里需要注意一个细节很多 mdns 接口的回调线程和 UI 线程不是同一个。如果你在回调里直接去操作 UI或者把结果转换成 Dart 侧数据需要做线程切换。不过如果只是把数据封装成 Map 并通过 EventChannel 发送一般没有跨线程性能问题因为 EventChannel 底层会自动处理线程切换。4.4 把原生回调原样转成 Flutter 事件流在鸿蒙侧拿到 mdns 的discoverService事件后不能直接塞给 Flutter需要转换成标准格式。我一般用一个DiscoveredServiceInfo到Map的转换函数把服务信息统一封装成interface MdnsService { name: string; host: string; port: number; txt: Recordstring, string; type: string; }然后在启动发现时把 EventChannel 的 sink 保存下来当系统回调discoverService时把这条数据推给 Dart 层。这里必须强调生命周期问题。在 Flutter 页面进入后台、发现任务结束时一定要调用原生侧的 stopDiscovery 或者释放 EventChannel否则会造成事件泄漏。鸿蒙系统不会因为这个崩溃但你会发现离开页面再回来时事件流里出现了大量重复回调因为原来的监听还在。5. 从零跑通“设备发现设备配对”的完整实操记录接口设计完了整个链路能不能用还得实测。我最近的实验环境是两台 OpenHarmony 设备 一台 Linux 开发机同一个 WiFi 路由器下。设备 A 是一个带 Flutter 应用的控制端设备 B 是一个被发现的“智能灯具”——其实就是个 Flutter 应用模拟的 UDP socket 服务端。5.1 服务端发布一次可用的控制协议思路设备 B 的 Flutter 应用启动时注册了一个_led._tcp服务同时监听 UDP 8080 端口。这里的关键是 UDP 服务必须和 mdns 注册的端口保持一致否则发现没问题后续通信完全失败。设备 B 侧代码大致如下import dart:io; import package:multicast_dns/multicast_dns.dart; class LedDevice { final _socket RawDatagramSocket.bind(InternetAddress.anyIPv4, 8080); final _mdns MulticastDns.instance; Futurevoid start() async { await _socket; _socket.then((socket) { socket.listen((event) { if (event RawSocketEvent.read) { final datagram socket.receive(); if (datagram ! null) { final msg String.fromCharCodes(datagram.data); // 解析控制命令例如 ON / OFF / COLORxxxx } } }); }); _mdns.registerService( name: LedDevice-001, type: _led._tcp.local., port: 8080, txt: {model: demo-led, fw: 1.0.0}, ); } }这里我故意把RawDatagramSocket.bind和MulticastDns.instance.registerService放在一起是为了提醒你服务注册动作发生在网络绑定之后。如果你在 initState 里注册服务但 socket 尚未 bind 成功局域网里其他设备可能已经发现服务并尝试连接而 UDP 端口还没打开会导致第一批连接失败。5.2 客户端发现与真实连接设备 A 的 Flutter 应用在启动后开始扫描_led._tcp.local把发现的设备列表渲染到界面点击设备后就向目标地址发送控制指令。void onDeviceTap(MdnsService service) { final address InternetAddress(service.host); final socket RawDatagramSocket.bind(InternetAddress.anyIPv4, 0); final message ON; socket.send(message.codeUnits, address, service.port); }运行过程中打印的日志大致是flutter: 发现服务: LedDevice-001._led._tcp.local. flutter: host: 192.168.1.66 flutter: port: 8080 flutter: txt: {model: demo-led, fw: 1.0.0}这里有一个重要观察第一次启动扫描可能要等 2 秒左右才能搜到设备第二次再启动发现时几乎瞬间就能返回。原因就是前面提到的 mDNS 缓存机制。所以如果用户是第一次安装 App 去扫设备预期应该给一个“正在扫描”的加载状态不要上来就展示空列表。5.3 实际操作中最大的拦路虎路由器 AP 隔离这个实验最耗时的一个坑不是代码而是路由器。我在第一次跑通流程时控制端怎么也发现不了服务端。两台设备互相 ping 能通说明二层网络没问题但 mDNS 就是没响应。后来检查路由器配置才发现厂商默认开启了“AP 隔离”功能。这个功能会让无线客户端之间无法直接通信虽然它们都能访问外网。mDNS 报文自然也被隔离掉了。把 AP 隔离关掉之后设备秒现。这个问题在办公网络、访客网络里特别常见。你写好的应用到了客户现场很可能因为对方路由器开启了 AP 隔离而“失灵”。所以做局域网发现功能时一定要让现场网络把客户端隔离选项关掉或者在应用里做一个“手动添加设备”的兜底方案不能完全依赖组播。6. 高频率问题排查与避坑手册读到这里你应该已经有了一个能跑的服务发现链路。现实问题是多变的我把自己和团队实际排查过的几个典型问题整理成一张速查表方便你遇到相似问题时快速定位。现象常见原因排查/处理方法扫不到任何服务网络权限缺失、AP 隔离、防火墙拦截检查系统权限声明、关掉 AP 隔离、打开防火墙 5353 端口只能扫到部分服务设备侧 TTL 缓存、网络规模过大等待 TTL 超时或重新走完整查询周期服务出现在列表但连接不上SRV/A 记录返回多网卡 IP确认设备当前启用网卡的 IP必要时在代码里过滤非局域网地址重复收到大量相同服务没有正确停止监听检查 MulticastDns.stop 和 EventChannel cancel 是否调用第一次能发现第二次失败未处理生命周期、单例监听冲突统一管理 start/stop页面销毁时释放监听鸿蒙上调用方法报 MissingPluginException原生侧 MethodChannel 未注册检查 ohos 工程里是否初始化/注册了自定义模块或未正确配置 oh-package.json5设备自己无法被本机发现mDNS 默认不回环如果需要自发现走服务注册方主动记录或构造本机实例下面挑几个展开说。6.1 权限与防火墙导致的“隐形设备”如果你已经确认网络环境没有问题仍然扫不到任何服务第一优先怀疑权限。OpenHarmony 上缺ohos.permission.INTERNET的应用其实是可以正常启动的你不会看到崩溃但所有网络请求都会静默失败。这比 Android 更隐蔽。Android 缺权限的时候一般会抛异常OpenHarmony 可能连日志都不打直接丢包。在 Linux 开发机上调试 mDNS 时同样会遇到防火墙问题。很多人习惯用systemctl stop firewalld来验证我个人不太建议直接关闭系统防火墙而是在 firewalld 里放行 UDP 5353 端口的组播流量或者把对应网络接口设为信任域。毕竟你面向用户交付时不能要求用户关闭防火墙。6.2 多网卡设备导致解析到错误 IPmDNS 会为设备的所有可用网卡广播记录。比如一台开发板同时连着 WiFi 和以太网它可能在 WiFi 网卡上是 192.168.1.50在以太网卡上是 192.168.2.10。客户端如果和它不在同一网段按错误 IP 去连接自然连不上。这个问题在手机热点场景特别明显。手机同时开了蜂窝数据和 WiFi 热点时OpenHarmony 设备获取到的局域网地址可能是 192.168.43.x而你的 App 在手机侧拿到的地址也许是 192.168.1.x。两者不在同一网段mDNS 广播虽然能收到但连接却失败。我的建议是客户端拿到service.host后不要直接用先把自身网段和目标地址做一次子网判断排除明显不在同一网段的 IP。如果服务返回了多个 A 记录优先选择与本地网卡同网段的一个。6.3 查询结果里的.local.尾部点别误判multicast_dns 返回的service.name和service.host经常是带末尾点的形式比如LedDevice-001._led._tcp.local.。有些开发者会把末尾点和字符串拼接后去做 URL结果得到http://192.168.1.66.:8080这种非法地址。正确的清理方式是String cleanName(String name) name.endsWith(.) ? name.substring(0, name.length - 1) : name;同理如果做 DNS TXT 键值解析要注意 TXT 里的 key 可能是小写有些 SDK 实现还会自动排序不要依赖顺序。6.4 服务消失的时间比你想象的慢mDNS 记录在正常下线时会主动广播 TTL0 的记录让其他设备删除缓存。但如果是断电、崩溃、断网其他设备上的缓存只能在 TTL 超时后自动清理。默认 TTL 可能是 120 秒甚至更长这会导致你的 App 里出现“幽灵设备”设备已经下线了列表里还显示着。要缓解这个问题可以在业务层维持一个心跳机制。比如每 5 秒查询一次服务如果 3 个心跳周期没有收到该设备的任何 mDNS 报文就在 UI 层把它标记为离线或移除。单纯依赖 mDNS 的过期通知在异常断网场景下不够实时。7. 一点个人经验总结回到标题里的“零配置网络”很多人第一反应是“哦就是局域网内广播一下找到设备”。真正做完一轮适配后你会发现mDNS 只是整个零配置网络里的一环真正难的是让它在一堆复杂网络环境里稳定工作。我在这次 Flutter for OpenHarmony 适配中最大的收获是遇到跨平台插件不能运行时不要第一时间去改 Dart 层逻辑先静下来把协议链路捋清楚看看系统的网络策略、权限模型和防火墙规则是不是在配合你。很多问题用命令行工具比如dns-sd或avahi-browse都能快速验证网络环境本身是否支持服务发现。只有先排除底层网络因素再回头查代码才高效。如果让我给你一个落地建议在 Flutter 层把 multicast_dns 的纯 Dart 实现当作快速原型方案验证你周围网络环境是否支持 mDNS真正交付给鸿蒙用户时再用鸿蒙原生 mDNS 能力把底层替换掉上层接口保持不变。这套“接口优先、底层可替换”的设计让我在后来的适配工作中少走了很多弯路也希望对你有所帮助。
网站建设高端定制企业官网
RELATED

相关资讯

更多精彩内容,欢迎继续阅读

较早相关资讯

最新相关资讯

BlenderMCP:一句话指挥 Blender 3D 建模,十分钟跑通连接 2026/9/9 16:48:06

BlenderMCP:一句话指挥 Blender 3D 建模,十分钟跑通连接

BlenderMCP:一句话指挥 Blender 3D 建模,十分钟跑通连接 【免费下载链接】blender-mcp Community plugin to control Blender 3D with any LLM of your choice 项目地址: https://gitcode.com/GitHub_Trending/bl/blender-mcp 刚装好 BlenderMCP&…

阅读更多 →
LPC1768裸机移植FreeRTOS与LWIP实现TCP通信全流程解析 2026/9/9 16:48:06

LPC1768裸机移植FreeRTOS与LWIP实现TCP通信全流程解析

简介:面向LPC1768嵌入式开发者的一份完整移植参考工程,围绕在Cortex-M3平台上同时集成FreeRTOS实时操作系统与LWIP TCP/IP协议栈展开。资源共478个文件,压缩后仅1.59MB,以.h头文件与.c源码为主(分别有123个和119个&…

阅读更多 →
.NET控制台程序实战:从CSV高效读取到Word报表生成 2026/9/9 16:48:06

.NET控制台程序实战:从CSV高效读取到Word报表生成

说实话,接这个需求之前我脑子里浮现的还是三年前刚转.NET时的场景——拿着一堆CSV往系统里导数据,前端催、领导催、客户也催,我急得不行,写了一个Web界面来做数据导入和报表生成,结果光部署就折腾了两天。后来我才发现…

阅读更多 →
AI立体画打印机:从深度图到光栅成像的自动化工作流解析 2026/9/9 16:48:06

AI立体画打印机:从深度图到光栅成像的自动化工作流解析

把一张普通照片变成能裸眼看到深度的立体画,听起来像是一个“一键生成”的事。真做了才知道,立体画从来不是一张图片,而是一整条从深度计算、多视角渲染、像素交错到光栅贴合的生产线。看到“彗星插件AI自动立体画打印机”这个方案时&#xf…

阅读更多 →
【Springboot毕设全套源码+文档】基于springboot的家教信息匹配与预约系统的设计与实现(丰富项目+远程调试+讲解+定制) 2026/9/9 16:48:06

【Springboot毕设全套源码+文档】基于springboot的家教信息匹配与预约系统的设计与实现(丰富项目+远程调试+讲解+定制)

博主介绍:✌️码农一枚 ,专注于大学生项目实战开发、讲解和毕业🚢文撰写修改等。全栈领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围:&am…

阅读更多 →
Pajek动态网络分析:从时间维度挖掘网络演化规律与实战要点 2026/9/9 16:45:06

Pajek动态网络分析:从时间维度挖掘网络演化规律与实战要点

Pajek 这个老牌社会网络分析软件,在很多做网络分析的同行手里往往只被用来算点度中心度、画个静态社群图。说实话,这有点浪费。Pajek 真正让人眼前一亮的能力之一,是动态网络分析。也就是把时间维度塞进网络结构里,去看关系怎么生…

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

联系尧图顾问,获取一对一建站咨询

立即免费咨询 📞 400-888-8888
📞