首页/新闻资讯/正文详情

分布式软总线组件拆包:从发现到传输的源码解析

发布时间:2026/9/23 22:44:07 来源:云帆数科 栏目:资讯中心
分布式软总线组件拆包:从发现到传输的源码解析
简介这份资源是面向 OpenHarmony 底层开发者的分布式软总线组件源码包聚焦近场设备间统一通信管理能力的实现。它针对现实中 WiFi、蓝牙等多种通信方式差异大、链路融合共享与冲突难以处理的痛点提供不区分链路的设备发现连接、组网与传输能力涵盖基于 WiFi、蓝牙的设备发现连接、统一组网与拓扑管理以及支持消息、字节、流、文件的数据传输通道适合具备一定系统与网络编程基础的中高级开发者研读。资源包共约 2000 个文件以 702 个 h 头文件、531 个 c 与 433 个 cpp 源文件为主体辅以 137 个 gn、24 个 gni 构建脚本及 91 个 xml、70 个 init 配置整体约 3.7MB结构完整。内容涉及组网构建、连接管理、文件传输代理、分布式网络账本、P2P 与 FillP 连接、DFile 会话等模块可帮助读者梳理软总线发现、组网、传输的代码脉络与排错思路。目前已有 383 人学习下载。1. 分布式软总线组件拆包从发现到传输这套源码能跑通什么多设备通信最让人头疼的不是“连不上”而是“同一种业务在 WiFi 下能跑、换蓝牙就翻车”。分布式软总线要解决的就是这件事把 WiFi、蓝牙这些差异极大的物理链路抽象成统一接口让上层业务不关心底层走的是哪条路。这次拆的这套组件源码覆盖了软总线最核心的三块——发现、组网、传输具体文件包括lnn_net_builder.c、softbus_conn_ble_manager.c、softbus_conn_br_manager.c、disc_ble.c、p2p_v1_processor.c、fillp_conn.c、nstackx_dfile_session.c、nstackx_file_manager.c、client_trans_proxy_file_manager.c、lnn_distributed_net_ledger.c。它适合正在做 OpenHarmony 底层组件适配、或者想搞清楚近场设备互联到底怎么落地的人。下面按“发现怎么触发、组网怎么建、传输怎么选通道”这条线把每个模块的职责和可复现的操作拆开讲。2. 发现与组网disc_ble.c和lnn_net_builder.c怎么串起来2.1 蓝牙发现入口disc_ble.c的广播与扫描逻辑disc_ble.c是蓝牙发现的核心负责 BLE 广播包的组装、发送以及扫描回调的分发。它不直接处理连接只负责“让对方知道自己存在”和“发现别人”。常见做法是设备上线后先启动广播广播内容里带设备标识和能力位同时启动扫描收到广播后回调给上层做设备匹配。下面这段是广播启动的典型调用链参数需要按实际设备能力调整// disc_ble.c 中启动 BLE 广播的核心逻辑 static int StartBleAdv(void) { BleAdvParam param {0}; param.advType BLE_ADV_TYPE_CONNECTABLE; // 可连接广播组网需要 param.advInterval BLE_ADV_INTERVAL_128MS; // 广播间隔太短耗电太长发现慢 param.txPower BLE_TX_POWER_HIGH; // 发射功率影响发现距离 param.channelMap BLE_ADV_CHANNEL_ALL; // 37/38/39 三通道全开 int ret BleStartAdv(param); if (ret ! SOFTBUS_OK) { SOFTBUS_LOGE(StartBleAdv failed, ret%d, ret); return ret; } return SOFTBUS_OK; }逻辑说明advType选可连接广播是因为后续组网要基于这个广播建立 GATT 连接advInterval设 128ms 是平衡功耗和发现速度的常用值如果设备是常供电的可以降到 32ms 加快发现。channelMap全开是为了避免单一通道干扰导致发现失败。参数改错最直接的表现是广播发出去了但对方扫不到或者扫到了连不上。扫描侧的回调在disc_ble.c里通过BleScanCallback注册收到广播后先做设备类型过滤再交给lnn_net_builder.c做设备信息入库。2.2 组网状态机lnn_net_builder.c如何管理设备上线与拓扑lnn_net_builder.c是组网的大脑维护了一个设备状态机发现到设备后先标记为DEVICE_STATE_DISCOVERED发起连接后变DEVICE_STATE_CONNECTING连接成功且认证通过后变DEVICE_STATE_ONLINE。每个状态迁移都有对应的超时和重试。关键函数是LnnNetBuilderOnDeviceFound和LnnNetBuilderOnConnectResult。前者把发现到的设备信息写入lnn_distributed_net_ledger.c管理的设备账本后者根据连接结果更新状态并触发拓扑刷新。// lnn_net_builder.c 中设备上线后的拓扑更新 int LnnNetBuilderOnDeviceOnline(const DeviceInfo *info) { if (info NULL) { return SOFTBUS_INVALID_PARAM; } // 写入设备账本后续传输模块靠这个查设备 int ret LnnAddDeviceToLedger(info); if (ret ! SOFTBUS_OK) { SOFTBUS_LOGE(add to ledger failed); return ret; } // 通知拓扑变化触发上层业务刷新设备列表 LnnNotifyTopologyChanged(); return SOFTBUS_OK; }参数说明DeviceInfo里必须带deviceId、devType、connAddr三个字段缺一个账本就写不进去。LnnNotifyTopologyChanged是同步调用如果上层业务处理慢会阻塞组网线程常见做法是丢到独立任务队列里异步通知。2.3 设备账本lnn_distributed_net_ledger.c的读写与一致性lnn_distributed_net_ledger.c本质是一个带锁的哈希表key 是deviceIdvalue 是设备完整信息。它提供LnnAddDeviceToLedger、LnnRemoveDeviceFromLedger、LnnGetDeviceInfo三个主要接口。读写都要加锁因为发现线程和传输线程会并发访问。踩坑最多的地方是设备下线时账本没清干净导致传输模块拿到一个已经断开的设备地址去发数据直接超时。正确做法是在LnnNetBuilderOnDeviceOffline里先调LnnRemoveDeviceFromLedger再通知拓扑变化。3. 连接管理BLE 和 BR 两条链路的差异化处理3.1softbus_conn_ble_manager.cBLE 连接的生命周期BLE 连接管理负责 GATT 连接的建立、MTU 协商、连接参数更新和断开重连。核心结构是BleConnInfo里面存了connId、mtu、state、callback。连接建立后第一件事是协商 MTU默认 23 字节协商到 512 字节才能跑文件传输。// softbus_conn_ble_manager.c 中 MTU 协商后的回调 static void OnMtuChanged(uint32_t connId, uint16_t mtu) { BleConnInfo *info GetBleConnInfo(connId); if (info NULL) { return; } info-mtu mtu; // MTU 小于 128 时传输效率极低记录告警 if (mtu BLE_MIN_EFFICIENT_MTU) { SOFTBUS_LOGW(ble mtu too small: %u, mtu); } // 通知传输层可以开始发数据 NotifyConnReady(connId, mtu); }参数说明BLE_MIN_EFFICIENT_MTU一般设 128低于这个值文件传输会频繁分片速度掉得厉害。MTU 协商失败时mtu保持默认 23这时候传输层应该降级到小消息模式而不是硬发大包。3.2softbus_conn_br_manager.c经典蓝牙的 RFCOMM 通道BR 链路走的是 RFCOMMsoftbus_conn_br_manager.c管理 socket 的创建、连接和读写。和 BLE 不同BR 没有 MTU 协商但需要处理 RFCOMM 通道号的分配。常见做法是服务端监听固定通道号客户端连接时先做 SDP 查询拿到通道号再连。// softbus_conn_br_manager.c 中建立 RFCOMM 连接 static int BrConnect(const BrAddr *addr) { int sock socket(AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM); if (sock 0) { return SOFTBUS_ERR; } struct sockaddr_rc rcAddr {0}; rcAddr.rc_family AF_BLUETOOTH; rcAddr.rc_bdaddr addr-bdAddr; rcAddr.rc_channel GetRfcommChannel(addr); // 从 SDP 缓存拿通道号 int ret connect(sock, (struct sockaddr *)rcAddr, sizeof(rcAddr)); if (ret 0) { close(sock); return SOFTBUS_ERR; } return sock; }参数说明rc_channel不能写死不同设备的 RFCOMM 通道号可能不同必须通过 SDP 查询获取。GetRfcommChannel内部有缓存第一次查完存起来后续直接用。如果连接返回ECONNREFUSED大概率是通道号不对或者对端没监听。3.3 两条链路的选型与切换什么时候用 BLE什么时候用 BRBLE 适合低功耗、小数据量场景比如设备发现和信令交互BR 适合大数据量、对延迟不敏感的场景比如文件传输。实际组网中常见做法是发现阶段用 BLE 广播组网信令走 BLE GATT文件传输自动切到 BR 或 WiFi P2P。切换逻辑在lnn_net_builder.c里根据数据类型判断消息和字节走 BLE流和文件走 BR 或 P2P。如果 BR 不可用降级到 BLE 分片传输但速度会明显下降。4. 传输通道P2P、FillP 和文件传输的落地细节4.1p2p_v1_processor.cWiFi P2P 的协商与建连P2P 传输的前提是 WiFi P2P 组网成功。p2p_v1_processor.c处理 GOGroup Owner协商、DHCP 分配和 socket 建立。协商阶段双方交换 GO Intent 值值大的当 GO值相同则随机。GO 确定后启动 DHCP 服务端客户端拿 IP 后建 socket。// p2p_v1_processor.c 中处理 GO 协商结果 static void OnGoNegotiationResult(int result, const char *goMac) { if (result P2P_GO_NEG_SUCCESS) { // 协商成功启动 DHCP 或请求 IP if (IsGo()) { StartDhcpServer(); } else { RequestDhcpIp(); } // 通知传输层 P2P 通道就绪 NotifyP2pReady(goMac); } else { SOFTBUS_LOGE(go negotiation failed: %d, result); // 协商失败降级到 BR FallbackToBr(); } }参数说明goMac是 GO 的 MAC 地址后续 socket 连接要用。FallbackToBr是降级逻辑P2P 协商失败不能直接报错要自动切到 BR 保证业务不中断。4.2fillp_conn.c可靠传输的拥塞控制与重传FillP 是软总线自研的可靠传输协议fillp_conn.c实现了滑动窗口、ACK 确认和超时重传。它比 TCP 轻量适合近场低延迟场景。核心参数是窗口大小和 RTO重传超时。// fillp_conn.c 中发送窗口的初始化 static void FillpInitSendWindow(FillpConn *conn) { conn-sendWindow FILLP_DEFAULT_WINDOW; // 默认 64 个包 conn-rto FILLP_MIN_RTO; // 最小 RTO 100ms conn-maxRetry FILLP_MAX_RETRY; // 最大重传 5 次 // 根据链路质量动态调整 if (conn-linkQuality LINK_QUALITY_POOR) { conn-sendWindow FILLP_MIN_WINDOW; // 链路差时缩小窗口 conn-rto FILLP_MAX_RTO; // 拉长重传超时 } }参数说明FILLP_DEFAULT_WINDOW设 64 是吞吐和内存的折中链路质量差时降到 16 避免拥塞。rto最小 100ms最大 1s根据 RTT 动态计算。重传超过maxRetry直接断连通知上层。4.3nstackx_dfile_session.c与nstackx_file_manager.c文件分片与重组文件传输走的是 dfile 协议nstackx_dfile_session.c管理会话nstackx_file_manager.c管理文件分片。大文件切成固定大小的块每块带序号接收端按序号重组。分片大小默认 64KB可根据 MTU 调整。// nstackx_file_manager.c 中文件分片逻辑 static int SplitFileToBlocks(const char *filePath, uint32_t blockSize) { int fd open(filePath, O_RDONLY); if (fd 0) { return SOFTBUS_ERR; } uint32_t index 0; uint8_t *buf malloc(blockSize); ssize_t readLen; while ((readLen read(fd, buf, blockSize)) 0) { // 每块带序号和总块数接收端靠这个重组 SendBlock(index, readLen, buf); } free(buf); close(fd); return SOFTBUS_OK; }参数说明blockSize默认 64KB如果底层 MTU 只有 512 字节分片太大会导致底层再分片效率反而低。常见做法是blockSize设为 MTU 的整数倍。index从 0 开始接收端按序写入临时文件全部收齐后 rename 成目标文件。4.4client_trans_proxy_file_manager.c代理层的文件传输调度代理层负责把上层的文件传输请求路由到正确的通道P2P/BR/BLE并管理传输优先级。多个文件同时传时按优先级排队小文件优先避免大文件阻塞信令。// client_trans_proxy_file_manager.c 中的传输调度 static int ProxySendFile(const FileRequest *req) { // 根据文件大小和当前通道负载选路 if (req-fileSize LARGE_FILE_THRESHOLD IsP2pAvailable()) { return SendViaP2p(req); } else if (IsBrAvailable()) { return SendViaBr(req); } else { return SendViaBle(req); // 最后降级到 BLE } }参数说明LARGE_FILE_THRESHOLD一般设 1MB超过走 P2P。IsP2pAvailable检查 P2P 通道是否就绪没就绪就降级。降级顺序是 P2P BR BLEBLE 最慢但最稳。5. 避坑与排查这套组件跑起来最容易翻车的五个点5.1 现象BLE 广播发出去了但对方扫不到原因广播通道被占用或者广播间隔太长。常见于多设备同时广播的场景37/38/39 三个通道如果只开了一个碰撞概率高。解决channelMap设为BLE_ADV_CHANNEL_ALLadvInterval降到 32ms 测试。如果还不行检查设备是否支持 BLE 5.0 的扩展广播老设备只支持传统广播扫描窗口要匹配。5.2 现象组网成功但传输一直超时原因lnn_distributed_net_ledger.c里的设备地址过期了。设备下线后账本没清传输模块拿到旧地址去连必然超时。解决在LnnNetBuilderOnDeviceOffline里强制调LnnRemoveDeviceFromLedger并且传输前先LnnGetDeviceInfo校验设备状态状态不是ONLINE直接返回错误。5.3 现象P2P 协商成功但 socket 连不上原因DHCP 没拿到 IP 或者防火墙拦了。P2P 组网后 GO 端要启动 DHCP 服务端客户端请求 IP这一步失败的话 socket 层根本没法通信。解决检查StartDhcpServer是否返回成功客户端RequestDhcpIp超时时间设长一点默认 5s可以调到 10s。如果 IP 拿到了还连不上检查 socket 绑定的是不是 P2P 网卡的地址。5.4 现象文件传输到 99% 卡住原因最后一个分片丢了或者 ACK 没收到。FillP 的重传机制在最后一个包上容易出问题因为发送端已经关了窗口接收端还在等。解决在nstackx_file_manager.c里加一个收尾超时超过 3s 没收到最后一块就主动请求重传。或者把maxRetry调大确保最后一个包有足够重传机会。5.5 现象BLE 和 BR 同时连接时互相干扰原因两条链路共用天线BLE 广播和 BR 数据传输抢射频资源。常见于手机同时开 BLE 和 BR 的场景。解决在softbus_conn_ble_manager.c和softbus_conn_br_manager.c之间加互斥锁BR 传输时暂停 BLE 广播传输完再恢复。或者把 BLE 广播间隔拉长减少射频占用。6. 进阶技巧用lnn_net_builder.c的状态机做链路质量探测这套组件里最容易被忽略的是lnn_net_builder.c的状态机其实可以拿来当链路质量探测器。每次状态迁移的时间戳都记下来发现到连接的时间、连接建立的时间、认证的时间这三个值能反映链路质量。我一般会在LnnNetBuilderOnConnectResult里加一段统计逻辑// 在 lnn_net_builder.c 中加链路质量统计 static void RecordLinkQuality(const DeviceInfo *info, uint64_t costMs) { // costMs 是从发起连接到连接成功的耗时 if (costMs LINK_QUALITY_GOOD_MS) { info-linkQuality LINK_QUALITY_GOOD; } else if (costMs LINK_QUALITY_FAIR_MS) { info-linkQuality LINK_QUALITY_FAIR; } else { info-linkQuality LINK_QUALITY_POOR; } // 写入账本传输模块选路时参考 LnnUpdateDeviceLinkQuality(info-deviceId, info-linkQuality); }参数说明LINK_QUALITY_GOOD_MS设 200msLINK_QUALITY_FAIR_MS设 500ms超过 500ms 算差。这个值不是固定的BLE 连接普遍比 BR 慢可以按链路类型分别设阈值。传输模块在client_trans_proxy_file_manager.c里选路时优先选LINK_QUALITY_GOOD的通道差的通道只跑信令不跑数据。验证方法很简单找两台设备一台正常距离一台拉远到 10 米外分别组网看costMs的差异。正常距离 BLE 连接大概 150ms 左右10 米外可能到 800ms 以上这时候传输就该切到 BR 或者 P2P。还有一个技巧是拿fillp_conn.c的 RTO 值反推链路质量。RTO 动态调整的过程中如果一直维持在最小值 100ms说明链路很稳如果频繁跳到 500ms 以上说明丢包严重这时候即使连接没断传输速度也会掉得厉害。我一般会在 FillP 的连接结构里加一个rtoHistory数组记录最近 10 次 RTO 值取平均作为链路质量的辅助判断。从那以后我每次调软总线传输都强制先跑一遍链路质量探测把costMs和 RTO 均值打出来再决定传输策略。这个习惯帮我省了很多“明明连上了但传不动”的排查时间。希望帮到你。本文还有配套的精品资源点击获取

相关推荐

PSO-LSTM股票预测:调整收盘价与超参数优化实战解析
PSO-LSTM股票预测:调整收盘价与超参数优化实战解析

简介:基于PSO-LSTM神经网络的股票调整收盘价预测Python源码.zip 面向金融数据挖掘初学者、期末大作业及课程设计学习者,提供一套可直接运行的预测实现。项目以粒子群优化(PSO)算法改进LSTM超参数选择,对多种股票调整后… · 2026/9/23 22:44:07

微信小程序图书馆预约系统毕业设计实战指南
微信小程序图书馆预约系统毕业设计实战指南

简介:本资源是一套完整的微信小程序毕业设计项目,面向计算机相关专业本科生及初学者,聚焦图书馆自习室预约场景,解决校园场景下空间资源线上化管理与用户信用体系构建问题。压缩包共5个文件,含2个RAR源码包&#xff08… · 2026/9/23 22:44:01

小智首批设备放量:接入名单与故障恢复的关键策略
小智首批设备放量:接入名单与故障恢复的关键策略

小智首批设备要放量,我第一时间想到的不是刷多少台机器,也不是固件编译参数怎么调,而是三个字:别翻车。做过硬件接入的人都懂,小智这种基于ESP32的AI语音助手方案,和纯软件项目放量完全是两码事。软件出bug… · 2026/9/23 22:43:49

Formily reactive-vue observer 完全指南:把 Vue 组件渲染变成可自动追踪的 Reaction
Formily reactive-vue observer 完全指南:把 Vue 组件渲染变成可自动追踪的 Reaction

前端UI组件 【免费下载链接】formily 📱🚀 🧩 Cross Device & High Performance Normal Form/Dynamic(JSON Schema) Form/Form Builder -- Support React/React Native/Vue 2/Vue 3 项目地址: https://gitcode.com/gh_mirrors… · 2026/9/24 2:13:38

小炒鸡肝做法详解:从焯水到爆炒的结构化菜谱实战(Datawhale All-in-RAG 数据源篇)
小炒鸡肝做法详解:从焯水到爆炒的结构化菜谱实战(Datawhale All-in-RAG 数据源篇)

教程人工智能大模型RAG 【免费下载链接】all-in-rag 🔍大模型应用开发实战一:RAG 技术全栈指南,在线阅读地址:https://datawhalechina.github.io/all-in-rag/ 项目地址: https://gitcode.com/datawhalechina/all-in-ra… · 2026/9/24 2:13:38

RenderDoc Python API 对象生命周期详解:句柄有效性、只读语义与内存安全实践
RenderDoc Python API 对象生命周期详解:句柄有效性、只读语义与内存安全实践

开发工具调试器图形学GPU 【免费下载链接】renderdoc RenderDoc is a stand-alone graphics debugging tool. 项目地址: https://gitcode.com/gh_mirrors/re/renderdoc 点击查看 免费下载 RenderDoc 的 Python API 是一层围绕 C API 的薄封装,这让大部分… · 2026/9/24 2:13:26

示波器探头选型与接地实战:从衰减比到补偿校准的避坑指南
示波器探头选型与接地实战:从衰减比到补偿校准的避坑指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/24 2:13:14

用 AI-Research-SKILLs 复现论文级配图:Andes 学术图表生成实战(Gemini 架构图 + matplotlib 数据图)
用 AI-Research-SKILLs 复现论文级配图:Andes 学术图表生成实战(Gemini 架构图 + matplotlib 数据图)

AI 技能人工智能大模型深度学习 【免费下载链接】AI-Research-SKILLs Comprehensive open-source library of AI research and engineering skills for any AI model. Package the skills and your claude code/codex/gemini agent will be an AI research agent with full hor… · 2026/9/24 2:13:01

EKS IRSA 调 SQS 仍 403:先补 GetQueueUrl
EKS IRSA 调 SQS 仍 403:先补 GetQueueUrl

一句话摘要:Pod 已挂 IRSA,策略里也有收发删,SDK 仍 AccessDenied——缺的往往是 GetQueueUrl,且不要去改节点角色。 目录 前言 一、先分清三条链 二、IRSA 只读盘点 三、收发删不够:补三个只读动作 四、队列不存在不是没权限 · 2026/9/24 2:12:31

基于YOLOv8的渔船作业监控系统:从环境搭建到边缘部署全流程
基于YOLOv8的渔船作业监控系统:从环境搭建到边缘部署全流程

简介:这是一套面向计算机、人工智能、自动化等专业学生与教师的毕业设计级项目资源,围绕YOLOv8实现渔船作业监控系统,可用于毕设、课程设计、大作业或项目立项演示。压缩包共97个文件,约24.21MB,以70个Python源码文件为… · 2026/9/24 0:00:13

1D-CNN时间序列建模实战:从Conv1d原理到工业落地
1D-CNN时间序列建模实战:从Conv1d原理到工业落地

简介:面向时间序列数据建模的一维卷积神经网络完整实现,适合深度学习入门者及需要快速验证时序模型的研究者,能够从音频、文本、传感器或股价等序列中挖掘局部特征与时间依赖。压缩包体积很小,只有3KB,内含3个Python脚… · 2026/9/24 0:00:26

柔软的L:汉语语流中被忽视的舌肌张力控制
柔软的L:汉语语流中被忽视的舌肌张力控制

1. 这个“L”不是字母表里的L,而是舌尖上的L最近在几个方言群和语音教学社群里,反复看到有人发一句:“也说字母L:柔软的长舌”。初看以为是英语发音课笔记,点开才发现全是方言爱好者、播音系学生、语言康复师甚至戏曲演… · 2026/9/24 0:00:44

了解更多?预约专属演示

我们的顾问将为您一对一讲解产品与方案

企业微信二维码