3、设备发现机制:CoAP协议详解、设备发现流程、服务发布与订阅、mDNS/DNS-SD在鸿蒙中的实现
3.1 设备发现——分布式软总线的“第一公里”
做分布式系统,最头疼的问题是什么?
我个人觉得,不是数据传输,也不是任务调度。而是——我怎么知道周围有哪些设备?
你想想看,手机要投屏到电视,电视得先被手机“看见”。智能家居里,灯泡要能被网关发现。鸿蒙的分布式软总线,第一步就是解决这个“看见”的问题。
说白了,设备发现就是分布式系统的“第一公里”。这步走不通,后面全是白搭。
核心观点:设备发现不是简单的“广播一下我在哪”,而是一套兼顾效率、功耗、可靠性的协议组合拳。鸿蒙在这块用了CoAP + mDNS/DNS-SD的混合方案。
我在项目中遇到过一种情况:两台设备明明在同一个Wi-Fi下,但就是互相发现不了。查了半天,发现是mDNS的组播包被路由器拦截了。嗯,这种坑踩过一次就记住了。
3.2 CoAP协议详解——轻量级的“HTTP”
先聊聊CoAP。全称是Constrained Application Protocol,受限应用协议。
为什么叫“受限”?因为它是给物联网设备用的。那些设备CPU弱、内存小、电池金贵,跑HTTP太奢侈了。CoAP就是为这种场景设计的。
3.2.1 CoAP vs HTTP:一张表看懂
| 对比项 | HTTP | CoAP |
|---|---|---|
| 传输层 | TCP(可靠但重) | UDP(轻量但不可靠) |
| 报文格式 | 文本(冗长) | 二进制(紧凑) |
| 头部大小 | 通常几百字节 | 固定4字节 |
| 请求方式 | GET/POST/PUT/DELETE | GET/POST/PUT/DELETE(一样) |
| 可靠性 | TCP保证 | CON/NON模式自己控制 |
| 适用场景 | PC、手机、服务器 | 传感器、嵌入式设备 |
你看,CoAP的请求方式跟HTTP一模一样。这是故意的——让开发者零成本迁移。但底层完全不同,CoAP跑在UDP上,报文是二进制,头部只有4个字节。
3.2.2 CoAP的四种报文类型
CoAP定义了四种报文,我习惯用“发消息”来理解:
- CON(Confirmable):需要确认的消息。就像你发微信问“在吗?”,对方得回“在”。
- NON(Non-confirmable):不需要确认的消息。就像你在群里发了个表情包,丢了就丢了,无所谓。
- ACK(Acknowledgement):确认消息。回复CON用的。
- RST(Reset):复位消息。告诉对方“我收不到,别发了”。
我的经验:设备发现场景下,我建议用NON模式。因为发现消息丢了可以重发,没必要每个包都确认。省电、省带宽。但服务订阅这种关键操作,必须用CON模式,确保对方收到了。
3.2.3 CoAP的观察者模式
CoAP还有一个很妙的设计——Observe模式。客户端可以“订阅”一个资源,服务端有变化时主动推送。
这跟HTTP的轮询完全不同。HTTP你得隔几秒问一次“变了没?”,CoAP是“变了我就告诉你”。
// 客户端发起观察请求(简化示意)
// 请求:GET /temperature (Observe: 0)
// 服务端第一次响应:2.05 Content (温度: 25°C)
// 温度变化时,服务端主动推送:2.05 Content (温度: 26°C)
// 温度再变化,再推送:2.05 Content (温度: 27°C)
我在做智能家居项目时,就用Observe模式监听传感器数据。温度变了、湿度变了,网关立刻知道。比轮询省了至少80%的网络流量。
3.3 设备发现流程——三步走
鸿蒙的设备发现,我总结为三步:广播、响应、确认。
- 广播发现请求:设备A通过CoAP的NON报文,向组播地址发送“谁在?”
- 设备响应:设备B收到后,回复一个CON报文,带上自己的设备信息(设备类型、服务列表等)。
- 确认建立:设备A回复ACK,双方建立初步连接。后续通过mDNS获取更详细的服务信息。
注意:这个流程不是一次性的。设备会定期广播,也会监听组播。新设备加入时,能快速被发现。我建议广播间隔设为3-5秒,太频繁费电,太慢影响体验。
3.4 服务发布与订阅——让设备“自我介绍”
设备被发现后,接下来要做什么?
自我介绍啊!
设备A发现设备B了,但不知道B能干什么。B是打印机?还是音箱?还是灯泡?这就需要服务发布。
3.4.1 服务发布
每个设备启动时,会向局域网发布自己的服务信息。格式通常是这样的:
服务类型: _hiam._tcp
服务名称: 客厅音箱
服务属性:
- device_id: "123456"
- device_type: "speaker"
- capabilities: ["audio_play", "volume_control"]
- ip: "192.168.1.100"
- port: 8080
这个信息通过mDNS广播出去。其他设备收到后,就知道“哦,原来有个音箱在客厅”。
3.4.2 服务订阅
服务订阅是反向操作。设备A说:“我对音频播放服务感兴趣,谁有就告诉我”。
鸿蒙里用的是DNS-SD(DNS Service Discovery)来实现订阅。设备A发送一个DNS查询,问“谁提供_hiam._tcp服务?”。所有提供该服务的设备都会回复。
避坑指南:我曾经遇到一个问题——设备A订阅了服务,但设备B上线时,A没有收到通知。原因是DNS-SD的缓存过期时间设得太长了。我建议TTL(生存时间)设为120秒,既减少网络流量,又能及时感知设备变化。
3.5 mDNS/DNS-SD在鸿蒙中的实现
mDNS(多播DNS)和DNS-SD(DNS服务发现)是鸿蒙设备发现的核心技术。说白了,就是没有DNS服务器也能做域名解析和服务发现。
3.5.1 mDNS的工作原理
传统DNS需要一台服务器。你问“www.baidu.com的IP是多少?”,服务器告诉你。
mDNS不需要服务器。设备直接向组播地址224.0.0.251(IPv4)或FF02::FB(IPv6)发问:“谁知道speaker.local的IP?”
拥有这个名字的设备听到后,直接回复:“我就是,我的IP是192.168.1.100”。
3.5.2 鸿蒙的mDNS实现特点
鸿蒙对mDNS做了几个关键优化:
- 多网卡支持:Wi-Fi、蓝牙、以太网同时工作,mDNS在所有网卡上广播。
- 缓存机制:设备信息缓存到本地,减少重复查询。我建议缓存大小设为256条,够用又不占内存。
- 冲突检测:两个设备取了同一个名字怎么办?mDNS有自动冲突检测和重命名机制。
- 低功耗模式:设备休眠时,由代理节点代为响应mDNS查询。
3.5.3 DNS-SD的服务发现流程
DNS-SD在mDNS之上,专门做服务发现。流程是这样的:
- 客户端查询PTR记录:
_hiam._tcp.local→ 获取服务实例列表 - 客户端查询SRV记录:
客厅音箱._hiam._tcp.local→ 获取主机名和端口 - 客户端查询TXT记录:
客厅音箱._hiam._tcp.local→ 获取服务属性 - 客户端查询A/AAAA记录:
音箱主机名.local→ 获取IP地址
你看,四步查询,就把一个服务的所有信息拿到了。我在调试时经常用dns-sd -B _hiam._tcp local命令来查看当前网络上有哪些服务。
重要提醒:mDNS/DNS-SD依赖组播。有些企业网络会禁用组播,导致设备发现失败。我在客户现场就遇到过——IT部门为了安全,把组播全封了。解决方案是改用单播发现,或者让IT开白名单。
3.6 知识体系总览
下面这张图,是我梳理的本章知识体系。你看一眼,就能把CoAP、mDNS、DNS-SD的关系理清楚。
3.7 小结
这一章我们聊了鸿蒙设备发现的完整链路。从CoAP的轻量级通信,到mDNS/DNS-SD的服务发现,再到设备发现的三步流程。
我个人觉得,理解设备发现的关键在于:它不是单一协议,而是组合拳。CoAP负责轻量通信,mDNS负责名字解析,DNS-SD负责服务发现。三者配合,才能让设备在局域网内快速“找到彼此”。
嗯,下一章我们会深入聊聊数据传输。但今天先到这里,你先把设备发现吃透。这块搞明白了,后面的分布式通信就顺了。
公众号:蓝海资料掘金营,微信deep3321