dsoftbus-软总线中多层网络的通信栈

前言:

经典的dsoftbus 使用WiFi链路作为发现、设备发现的网络层,本文结合代码简析其作用

1. 模块架构分层

在 dsoftbus的通信栈中,CoAP 起到了承上启下的关键作用。它向下屏蔽了 WiFi 物理链路的复杂性,向上为设备发现(Discovery)提供标准的信令通道。

1.1协议报文在网络层的封装

2. 网络层的操作

2.1 网络接口的动态感知与绑定 (Interface Binding)

DSoftBus 并非简单地监听 0.0.0.0,而是采用特定接口绑定 (Interface Binding) 策略。这允许它在复杂的网络环境(如同时连接 WiFi 和热点)中精确控制数据流向。

核心机制:UpdateLocalNetworkInterface

该函数是网络层与应用层的"铰链"。它轮询系统网络接口,一旦发现 IP 变化,立即触发 CoAP 服务的重置。

  • 源码逻辑分析 (nstackx_device.c):
    1. 遍历接口 :系统启动或收到 Netlink 事件时,遍历 wlan0, p2p0, eth0 等接口。
    2. IP 校验 :检查接口是否分配了有效 IP (ipAddr.s_addr != 0)。
    3. 定向初始化 :调用 CoapServerInitWithIdx,传入具体的 IP 地址。这意味着 DSoftBus 会为每个有效接口创建一个独立的 CoAP Server 实例。

|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| void UpdateLocalNetworkInterface() { foreach (interface in system_interfaces) { if (interface.has_ip && interface.ip_changed) { // 销毁旧的 Socket CoapServerDestroy(interface.old_ip); // 在新 IP 上重新绑定 CoAP 服务 CoapServerInitWithIdx(interface.new_ip, interface.index); } } } |

2.2 Socket 创建与广播机制 (Socket & Broadcast)

在局域网设备发现中,DSoftBus 优先选择广播 (Broadcast) 而非组播。这是因为广播在家庭路由器中的兼容性最好,且无需路由器支持 IGMP Snooping。

核心实现:CoapCreateUdpClientEx

  • Socket 类型SOCK_DGRAM (UDP)。
  • 端口绑定 :默认绑定 5683 (CoAP 标准端口)。如果被占用,可能会回退到动态端口。
  • 广播使能 :必须显式调用 setsockopt(SO_BROADCAST),否则操作系统会拦截发往 255.255.255.255 的包。

|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| // 关键代码路径: components/nstackx/nstackx_ctrl/core/mini_discover/coap_app.c static int32_t CoapCreateUdpClientEx(...) { int fd = socket(AF_INET, SOCK_DGRAM, 0); // 关键:绑定到特定网卡的 IP,而不是 INADDR_ANY // 这确保了广播包只从该网卡发出,不会“串台” bind(fd, (struct sockaddr *)&localAddr, ...); // 关键:开启广播权限 int opt = 1; setsockopt(fd, SOL_SOCKET, SO_BROADCAST, &opt, sizeof(opt)); return fd; } |

2.3 广播地址的获取策略

DSoftBus 如何知道往哪里发包?

  • 策略 :它通过 ioctl(SIOCGIFBRDADDR) 获取当前接口的子网广播地址 (例如 192.168.1.255),而不是全局广播地址 255.255.255.255
  • 优势:子网广播通常会被路由器限制在当前局域网段内,不会造成更大范围的网络风暴。

3. 链路层操作

3.1 多网卡上下文管理 (Context Management)

DSoftBus 为了支持同时在 WiFi Station (连接路由器) 和 WiFi P2P (直连) 模式下工作,设计了多实例上下文管理机制。

  • 全局管理数组 : g_coapCtxArr[NSTACKX_MAX_LISTENED_NIF_NUM]

    • 这是一个全局数组,每个元素对应一个物理网卡接口(如 wlan0, p2p0)。
    • 每个元素包含独立的 coap_context_t (libcoap 上下文) 和 epoll 任务句柄。
  • 隔离与并发:

    • UpdateLocalNetworkInterface 检测到新网卡时,会分配一个空闲的 index
    • 调用 CoapServerInitWithIdx 为该 index 创建独立的 Socket 和 CoAP 栈。
    • 优势 : 即使 wlan0 网络拥塞或出错,也不会影响 p2p0 上的设备发现,实现了故障隔离。

3.2 资源注册与路由 (Resource & Routing)

CoAP 服务器启动后,必须注册"资源"才能响应外部请求。这类似于 Web 服务器注册 URL 路由。

  • 核心函数 : CoapInitResourcesInner (位于 coap_discover.c)
对应 Handler 作用 传输类型
HndPostServiceDiscover 设备发现。处理对方发来的"你在哪?"请求,回复设备信息。 Non-confirmable (广播)
HndPostServiceMsg 服务消息。用于设备间协商 Session 参数、Auth 握手等关键指令。 Confirmable (单播)

4. 网络数据流转

4.1 接收流程:从网卡到业务回调

这是一个典型的异步事件驱动流程:

  1. Epoll 触发 : 内核检测到 UDP Socket 有数据,唤醒 CoAPEpollReadHandle
  2. Libcoap 处理 : 调用 coap_io_do_io -> recvfrom 读取数据包。
  3. 协议解析 : Libcoap 解析 CoAP Header,根据 URI (/d/d) 找到对应的 Handler。
  4. 业务处理 (HndPostServiceMsgEx) :
    • Payload 解析 : 调用 ParseServiceMsgFrame 解析 JSON 数据。
    • 去重 : RefreshMsgIdList 过滤重复的广播包。
    • 上报 : 调用 NotifyMsgReceived 将结构化的 DeviceInfo 传递给上层 (Discovery Service)。

如上图发送流程:从业务到网卡

  1. 业务触发 : 上层调用 CoapSendServiceMsgWithDefiniteTargetIp
  2. 报文构建 : CreateServiceMsgFrame 将 C 结构体序列化为 JSON 字符串。
  3. 路由选择 : 根据目标 IP 选择对应的 coap_context_t (即选择从哪个网卡发出)。
  4. CoAP 封装: 添加 CoAP Header (Type=CON, Code=POST, ID=...)。
  5. 物理发送 : sendto 将 UDP 包发出。

4.2 json关键数据格式

CoAP 只是信封,真正的信件内容是 JSON 格式的 Payload。

|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| { "deviceId": "UDID-Hash-Value...", // 设备唯一标识 "moduleName": "softbus", // 模块名称 "data": { // 业务数据 "devName": "My Phone", "devType": 14, // 14代表手机 "cap": 15 // 能力位图 (Bitmap) } } |

5. 发现流程的全生命周期

从 WiFi 连接成功的那一刻起,CoAP 层是如何响应并启动发现的?如下图:

6. 协议报文在网络层的封装

当 DSoftBus 发出一个发现请求时,线路上的比特流结构如下:

层级 协议头 关键字段值 作用
L2 Ethernet Dest MAC: FF:FF:FF:FF:FF:FF 链路层广播,确保 WiFi 芯片接收该帧
L3 IP Src IP: 192.168.1.100 Dst IP: 192.168.1.255 网络层广播,确保同一子网内的主机接收
L4 UDP Src Port: 5683 Dst Port: 5683 传输层定位,确保由 CoAP 服务处理
App CoAP Type: NON (Non-confirmable) Method: POST URI: /d/d 应用层指令,告知这是一个"设备发现"请求
Data Payload {"devId":"...", "cap":...} 业务数据,携带设备身份和能力信息

7. 总结:

DSoftBus 在 CoAP 与网络层的结合上体现了**"分而治之,精准控制"**的设计哲学:

  1. 不依赖全局广播:通过绑定特定网卡 IP 并计算子网广播地址,实现了对多网卡环境(如同时开启 WiFi 和 热点)的精准隔离。
  2. 动态热插拔:基于事件驱动的接口管理机制,使得设备在网络切换(如从家里带到公司)时,能毫秒级重启发现服务,用户无感。
  3. 标准与高效并存:利用标准的 Socket 接口和 CoAP 协议,但在实现上针对局域网广播场景做了深度优化。
相关推荐
L16247615 小时前
linux环境安装MySQL的详细步骤(二进制包形式)
linux·运维·mysql
默默在路上16 小时前
CentOS Stream 9 安装mysql8.0
linux·mysql·centos
游戏23人生16 小时前
QT linux下 虚拟键盘使用及注意事项
linux·qt·计算机外设
AAA.建材批发刘哥16 小时前
03--C++ 类和对象中篇
linux·c语言·开发语言·c++·经验分享
softshow102617 小时前
使用 Windows 子系统 WSL 安装 Ubuntu 22.04
linux·windows·ubuntu
wadesir17 小时前
简易制作LinuxShell完全指南(深入解析原理、设计与实践步骤)
linux·运维·服务器
水天需01018 小时前
HISTFILE 介绍
linux
CreasyChan18 小时前
VirtualBox 安装 CentOS 7.2
linux·运维·centos
AAA.建材批发刘哥18 小时前
04--C++ 类和对象下篇
linux·c++·经验分享·青少年编程