星语课程网
HarmonyOS 分布式软总线架构组成
来源:本站编辑
2024-10-28 09:32
14
一.HarmonyOS概述 ------------- ### 1.1 系统定义 HarmonyOS是一款“面向未来”、面向全场景(移动办公、运动健康、社交通信、媒体娱乐)的分布式操作系统。在传统的单设备系统能力的基础上,HarmonyOS提出了基于同一套系统能力、适配多种终端形态的分布式理念,能够支持手机、平板、智能穿戴。智慧屏、车机等多种终端设备。 * 对消费者而言,HarmonyOS 能够将生活场景中的各类终端进行能力整合,形成一个“超级虚拟终端”,可以实现不同的终端设备之间的快速连接、能力互助、资源共享,匹配合适的设备、提供流畅的全场景体验 * 对应用开发者而言,HarmonyOS 采用了多种分布式技术,使得应用程序的开发实现与不同终端设备的形态差异无关,降低了开发难度和成本。这能够让开发者聚焦上层业务逻辑,更加便捷、高效地开发应用。 * 对设备开发者而言,HarmonyOS 采用了组件化的设计方案,可以根据设备的资源能力和业务特征进行灵活裁剪,满足不同形态的终端设备对于操作系统的要求。 ### 1.2 技术特性 HarmonyOS系统的技术特性包含以下几种 #### 1.2.1 硬件互助、资源共享 * 分布式软总线:是多种终端设备的统一基座,为设备之间的互联互通提供了统一的分布式通信能力,能够快速发现并连接设备,高效地分发任务和传输数据。 * 分布式设备虚拟化:可以实现不同设备的资源融合、设备管理、数据处理,多种设备共同形成一个超级虚拟终端。针对不同类型的任务,为用户匹配并选择能力合适的执行硬件,让业务连续地在不同设备间流转,充分发挥不同设备的资源优势。 * 分布式数据管理:基于分布式软总线的能力,实现应用程序数据和用户数据的分布式管理。 * 分布式任务调度:基于分布式软总线、分布式数据管理、分布式 Profile 等技术特性,构建统一的分布式服务管理(发现、同步、注册、调用)机制,支持对跨设备的应用进行远程启动、远程调用、远程连接以及迁移等操作,能够根据不同设备的能力、位置、业务运行状态、资源使用情况,以及用户的习惯和意图,选择合适的设备运行分布式任务。 #### 1.2.2 一次开发,多端部署 HarmonyOS 提供了用户程序框架、Ability 框架以及 UI 框架,支持应用开发过程中多终端的业务逻辑和界面逻辑进行复用,能够实现应用的一次开发、多端部署,提升了跨设备应用的开发效率。  ### 1.2.3 统一OS,弹性部署 HarmonyOS 通过组件化和小型化等设计方法,支持多种终端设备按需弹性部署,能够适配不同类别的硬件资源和功能需求。支撑通过编译链关系去自动生成组件化的依赖关系,形成组件树依赖图,支撑产品系统的便捷开发,降低硬件设备的开发门槛。 * 支持各组件的选择(组件可有可无):根据硬件的形态和需求,可以选择所需的组件。 * 支持组件内功能集的配置(组件可大可小):根据硬件的资源情况和功能需求,可以选择配置组件中的功能集。例如,选择配置图形框架组件中的部分控件。 * 支持组件间依赖的关联(平台可大可小):根据编译链关系,可以自动生成组件化的依赖关系。例如,选择图形框架组件,将会自动选择依赖的图形引擎组件等。 1.3 系统架构 -------- HarmonyOS 整体遵从分层设计,从下向上依次为:内核层、系统服务层、框架层和应用层。系统功能按照“`系统 > 子系统 > 功能/模块`”逐级展开,在多设备部署场景下,支持根据实际需求裁剪某些非必要的子系统或功能/模块。HarmonyOS 技术架构如图所示。  二.分布式软总线 2.1 总线与分布式软总线 ------------- ### 2.1.1 总线 总线是一种内部结构,它是cpu、内存、输入、输出设备传递信息的公用通道,主机的各个部件通过总线相连接,外部设备通过相应的接口电路再与总线相连接,从而形成了计算机硬件系统。  在计算机系统中,各个部件之间传送信息的公共通路叫总线,微型计算机是以总线结构来连接各个功能部件的。 按照计算机所传输的信息种类,计算机的总线可以划分为`数据总线`、`地址总线`和`控制总线`,分别用来传输`数据`、`数据地址`和`控制信号`。 传统总线的典型特征: * 即插即用 * 高带宽 * 低时延 * 高可靠 * 标准 ### 2.1.2 分布式软总线 相较于传统计算机中的硬总线,鸿蒙系统中的分布式软总线是一条虚拟的、“无形”的总线。可以连接同处于一个局域网内部的所有鸿蒙设备(1+8+N,如下图所示),并且具有`自发现`、`自组网`、`高带宽`和`低时延`等特点。 > 1+8+N > 1:手机 > 8:车机、音箱、耳机、手表/手环、平板、大屏、PC、AR/VR > N:泛指其他IOT设备  2.2 异构网络组网 ---------- 软总线技术支持对不同协议的异构网络进行组网。传统场景下,需要蓝牙传输的两台设备必须都具有蓝牙,需要WiFi传输的设备必须都具有WiFi。而蓝牙/WiFi 之间是无法进行数据通信的。 软总线提出蓝牙/WiFi 融合网络组网技术(架构如下图所示),解决了不同协议设备进行数据通信的问题。使得多个鸿蒙设备能够自动构建一个逻辑全连接网络,用户或者业务开发者无需关心组网方式与物理协议。对于软件开发者来说软总线异构组网可以大大降低其开发成本。  2.3 软总线传输 --------- 传统协议的传输速率差异非常大,时延也难以得到保证。软总线传输通过“极简协议”实现以下三个目标: * 高带宽(High Speed) * 低时延(Low Latency) * 高可靠(High Reliability)  将中间的四层协议栈精简为一层提升有效载荷,有效传输带宽提升20% 极简协议在传统网络协议的基础上进行了增强,体现于以下几个方面: * 流式传输:基于UDP实现数据的保序和可靠传输; * 双轮驱动:颠覆传统TCP每包确认机制; * 不惧网损:摒弃传统滑动窗口机制,丢包快速恢复,避免阻塞; * 不惧抖动:智能感知网络变化,自适应流量控制和拥塞控制; 2.4 分布式软总线源码结构 -------------- 分布式软中线代码仓库地址如下: * [communication\_interfaces\_kits\_softbuskit\_lite](https://gitee.com/openharmony/communication_interfaces_kits_softbuskit_lite) * [communication\_services\_softbus\_lite](https://gitee.com/openharmony/communication_services_softbus_lite) 上述两个仓库分别对应它的接口和实现; 而`communication_services_softbus_lite`源码结构中,又分为`authmanager`、`discovery`、`trans_service`和兼容系统差别的`os_adapter`目录。  1. `discover`:提供基于 COAP 协议的设备发现机制; 2. `authmanager`:提供设备认证机制和知识库管理功能; 3. `trans_service`:提供身份验证和数据传输通道; 4. `os_adapter`:检测运行设备性能,决定部分功能是否执行。 ### 2.4.1 discover `discovery`单元提供了基于`coap`(Constrained Application Protocol,受限应用协议,RFC7252)协议的设备发现机制。 考虑到运行`HarmonyOS`的设备除了硬件性能较好的手机、电脑等设备,还有资源受限的物联网设备,这些设备的ram、rom相对较小。coap 协议支持轻量的可靠传输,采用 coap 协议,可以扩大组网范围。 discovery 的实现前提是确保发现端设备与接收端设备在同一个局域网内且能互相收到对方的报文。流程为以下三步: 1. 发现端设备,使用 `coap` 协议在局域网内发送广播; 2. 接收端设备使用 `PublishService` 接口发布服务,接收端收到广播后,发送 `coap` 协议单播给发现端; 3. 发现端设备收到回复单播报文,更新设备信息。 `discovery` 部分代码由两部分组成(目录如下图所示)。其中 `coap` 部分是 `coap` 协议的封装实现, `discovery_service` 是基于 `coap` 协议的设备间发现流程的实现。  #### coap * coap\_def.h:定义 coap 协议包的格式、报文结构,且使用 UDP 协议传输; * coap\_adapter.c:实现 coap 协议的编码、解码函数; * coap\_socket.c:实现 coap 包的发现、接收服务; * Coap\_discovery.c:实现基于 coap 协议的设备发现功能。本文件定义了 socket通讯过程 #### discovery\_service * comman\_info\_manager.h:定义了鸿蒙系统当前支持的设备类型与级别; * Discovery\_service.c:实现了设备暴露、发现和连接流程。这里需要注意的是,考虑到同一局域网下,主设备发出连接请求广播后,多个物联网设备都会回复单播应答报文从而造成信道冲突。为避免此情况发生,每个物联网设备均维护一套 信号量机制,实现多设备的有序等待。 ### 2.4.2 authmanager `authmanager` 单元提供了设备认证机制。设备通过加密和解密的方式,互相建立信任关系,确保在互联场景下,用户数据在正确的设备之间进行流转,实现用户数据的加密传输。软总线中定义加密和解密算法的内容在 `trans_service/utils/aes_gcm.h` 中,`authmanager` 中的处理流程如下图所示:   #### authmanager * auth\_conn.c:提供发送、接收、认证和获取密钥的功能; * auth\_interface.c:管理会话、链接、密钥节点,提供增删改查功能; * msg\_get\_deviceid.c:以 `cJSON` 格式获取各个设备的信息,包括设备 id、链接信息、设备名、设备类型等; * bus\_manager.c:创建不同的 `listen`,用以监听系统上有哪些 `device` 并创建新的 `device` 节点,以及节点数据的处理。`bus_manager.c` 主要由 `discovery` 单元调用,通过判断本文件中 `flag` 标志位决定是否启动总线(`start_bus()`函数)或关闭当前总线 (`stop_bus()`函数)。`discovery` 调用后,`bus_manager` 执行流程如图: * wifi\_auth\_manager.c:实现了链接管理和数据接收功能。  #### trans\_service 经过第一阶段:协议确定、设备发现,第二阶段:设备链接,软总线模块执行到了第三阶段:数据传输阶段,即目录中 `trans_service` 单元。`trans_service` 模块依赖于 `HarmonyOS` 提供的网络 `socket` 服务,向认证模块提供认证通道管理和认证数据的收发;向业务模块提供 `session` 管理和基于 `session` 的数据收发功能,并且通过 `GCM` 模块的加密功能提供收发报文的加密/解密保护。如下图所示为 `trans_service` 模块在系统架构中的位置:  该部分源码的结构及其功能如下:  在`libdistbus` 目录中,各源码文件的实现功能均已给出,其中需要注意的是,软总线启动后,设备在发现阶段基于`coap` 协议使用`udp` 数据报进行通讯。当设备认证通过,确认连接后,将会使用`TCP` 协议进行更加安全可靠的通讯。同发现阶段避免多设备同时向主机回复单播报文产生信道冲突一样,这里也维护了一套信号量机制避免多设备互连产生资源冲突。 三.编译与测试 3.1 基本环境 -------- 环境 版本 Linux操作系统 Ubuntu 20.04 gcc 9.3.0 3.2 编译过程 -------- ### 3.2.1 源码获取 本次项目源码来源于 [码云](https://gitee.com)的开源项目。通过下载OpenHarmony全量代码进行实验; 详细源码下载路径可通过官方说明文档获取,下载地址: [OpenHarmony开发者文档](https://gitee.com/openharmony/docs)   下载后,解压文件即可获得全量代码,其中软总线部分代码路径如下 > OpenHarmony/foundation/communication/services/softbus\_lite/ ### 3.2.2 前期准备 #### 将linux shell修改为bash 登录后复制 ls -l /bin/sh sudo dpkg-reconfigure dash # 选择 No #### 查看软总线依赖项 首先进入软总线代码路径,查看依赖文件BUILD.gn 登录后复制 cd OpenHarmony/foundation/communication/services/softbus_lite/ cat BUILD.gn   其中: * `include_dirs`包括了编译该组件所需头文件 * `softbus_lite_sources`包括了编译组件的源代码 #### 编写相应Makefile文件 > 根据个人路径不同,需要修改Makefile文件首部ROOT\_DIR的具体路径 登录后复制 ROOT_DIR:=/home/jeff/workspace/OpenHarmony INC_DIR:= \ $(ROOT_DIR)/foundation/communication/services/softbus_lite/discovery/coap/include \ $(ROOT_DIR)/foundation/communication/services/softbus_lite/os_adapter/include \ $(ROOT_DIR)/foundation/communication/interfaces/kits/softbus_lite/discovery \ $(ROOT_DIR)/third_party/cJSON \ $(ROOT_DIR)/third_party/bounds_checking_function/include \ $(ROOT_DIR)/foundation/communication/services/softbus_lite/discovery/discovery_service/include \ $(ROOT_DIR)/foundation/communication/services/softbus_lite/authmanager/include \ $(ROOT_DIR)/base/startup/interfaces/kits/syspara_lite \ $(ROOT_DIR)/foundation/communication/services/softbus_lite/trans_service/include/libdistbus \ $(ROOT_DIR)/foundation/communication/services/softbus_lite/trans_service/include/utils \ $(ROOT_DIR)/foundation/communication/services/softbus_lite/trans_service/source/libdistbus \ $(ROOT_DIR)/foundation/communication/services/softbus_lite/trans_service/source/utils \ $(ROOT_DIR)/kernel/liteos_a/lib/libsec/include \ $(ROOT_DIR)/foundation/communication/interfaces/kits/softbus_lite/transport \ $(ROOT_DIR)/base/security/interfaces/innerkits/hichainsdk_lite \ $(ROOT_DIR)/third_party/mbedtls/include \ $(ROOT_DIR)/base/security/frameworks/hichainsdk_lite/source/huks_adapter \ $(ROOT_DIR)/base/security/interfaces/kits/iam_lite \ $(ROOT_DIR)/foundation/communication/interfaces/kits/softbus_lite/discovery/ \ SRCS:= \ $(ROOT_DIR)/foundation/communication/services/softbus_lite/authmanager/source/auth_conn.c \ $(ROOT_DIR)/foundation/communication/services/softbus_lite/authmanager/source/auth_interface.c \ $(ROOT_DIR)/foundation/communication/services/softbus_lite/authmanager/source/bus_manager.c \ $(ROOT_DIR)/foundation/communication/services/softbus_lite/authmanager/source/msg_get_deviceid.c \ $(ROOT_DIR)/foundation/communication/services/softbus_lite/authmanager/source/wifi_auth_manager.c \ $(ROOT_DIR)/foundation/communication/services/softbus_lite/discovery/coap/source/coap_adapter.c \ $(ROOT_DIR)/foundation/communication/services/softbus_lite/discovery/coap/source/coap_discover.c \ $(ROOT_DIR)/foundation/communication/services/softbus_lite/discovery/coap/source/coap_socket.c \ $(ROOT_DIR)/foundation/communication/services/softbus_lite/discovery/coap/source/json_payload.c \ $(ROOT_DIR)/foundation/communication/services/softbus_lite/discovery/coap/source/nstackx_common.c \ $(ROOT_DIR)/foundation/communication/services/softbus_lite/discovery/coap/source/nstackx_device.c \ $(ROOT_DIR)/foundation/communication/services/softbus_lite/discovery/discovery_service/source/coap_service.c \ $(ROOT_DIR)/foundation/communication/services/softbus_lite/discovery/discovery_service/source/common_info_manager.c \ $(ROOT_DIR)/foundation/communication/services/softbus_lite/discovery/discovery_service/source/discovery_service.c \ $(ROOT_DIR)/foundation/communication/services/softbus_lite/os_adapter/source/L1/os_adapter.c \ $(ROOT_DIR)/foundation/communication/services/softbus_lite/trans_service/source/libdistbus/auth_conn_manager.c \ $(ROOT_DIR)/foundation/communication/services/softbus_lite/trans_service/source/libdistbus/tcp_session.c \ $(ROOT_DIR)/foundation/communication/services/softbus_lite/trans_service/source/libdistbus/tcp_session_manager.c \ $(ROOT_DIR)/foundation/communication/services/softbus_lite/trans_service/source/libdistbus/trans_lock.c \ $(ROOT_DIR)/foundation/communication/services/softbus_lite/trans_service/source/utils/aes_gcm.c \ $(ROOT_DIR)/foundation/communication/services/softbus_lite/trans_service/source/utils/message.c \ $(ROOT_DIR)/foundation/communication/services/softbus_lite/trans_service/source/utils/tcp_socket.c \ OBJS:= $(patsubst %.c, %.o, $(SRCS)) LIBS:= CC:=gcc CXXFLAGS:= -fPIC -Wall $(addprefix -I , $(INC_DIR)) $(LIBS) -Wno-deprecated all: $(CC) -c $(SRCS) $(CXXFLAGS) rm -rf ./obj mv *.o ./obj/ $(CC) -shared -o ./obj/libsoftbus_lite.so ./obj/*.o clean: rm -rf ./obj #### 编译并查看结果 登录后复制 make   3.3 测试 ------ ### 3.3.1 参考官网文档,编写测试文件 文档地址: [分布式通信子系统](https://gitee.com/openharmony/docs/blob/master/readme/%E5%88%86%E5%B8%83%E5%BC%8F%E9%80%9A%E4%BF%A1%E5%AD%90%E7%B3%BB%E7%BB%9FREADME.md) 登录后复制 #include
#include
#include
#include
#include
#include
#include
// 定义业务⾃身的业务名称,会话名称及相关回调 const char *g_pkgName = "BUSINESS_NAME"; const char *g_sessionName = "SESSION_NAME"; struct ISessionListener * g_sessionCallback= NULL; #define NAME_LENGTH 64 #define TRANS_FAILED -1 // 回调实现:接收对方通过SendBytes发送的数据,此示例实现是接收到对端发送的数据后回复固定消息 void OnBytesReceivedTest(int sessionId, const void* data, unsigned int dataLen) { printf("OnBytesReceivedTest\n"); printf("Recv Data: %s\n", (char *)data); printf("Recv Data dataLen: %d\n", dataLen); char *testSendData = "Hello World, Hello!"; SendBytes(sessionId, testSendData, strlen(testSendData)); return; } // 回调实现:用于处理会话关闭后的相关业务操作,如释放当前会话相关的业务资源,会话无需业务主动释放 void OnSessionClosedEventTest(int sessionId) { printf("Close session successfully, sessionId=%d\n", sessionId); } // 回调实现:用于处理会话打开后的相关业务操作。返回值为0,表示接收;反之,非0表示拒绝。此示例表示只接受其他设备的同名会话连接 int OnSessionOpenedEventTest(int sessionId) { char sessionNameBuffer[NAME_LENGTH+1]; if(GetPeerSessionName(sessionId,sessionNameBuffer,NAME_LENGTH) == TRANS_FAILED) { printf("GetPeerSessionName faild, which sessionId = %d\n",sessionId); return -1; } if (strcmp(sessionNameBuffer, g_sessionName) != 0) { printf("Reject the session which name is different from mine, sessionId=%d\n", sessionId); return -1; } printf("Open session successfully, sessionId=%d\n", sessionId); return 0; } // 向SoftBus注册业务会话服务及其回调 int StartSessionServer() { if (g_sessionCallback == NULL) { g_sessionCallback = (struct ISessionListener*)malloc(sizeof(struct ISessionListener)); } if (g_sessionCallback == NULL) { printf("Failed to malloc g_sessionCallback!\n"); return -1; } g_sessionCallback->onBytesReceived = OnBytesReceivedTest; g_sessionCallback->onSessionOpened = OnSessionOpenedEventTest; g_sessionCallback->onSessionClosed = OnSessionClosedEventTest; int ret = CreateSessionServer(g_pkgName, g_sessionName, g_sessionCallback); if (ret < 0) { printf("Failed to create session server!\n"); free(g_sessionCallback); g_sessionCallback = NULL; } return ret; } // 从SoftBus中删除业务会话服务及其回调 void StopSessionServer() { int ret = RemoveSessionServer(g_pkgName, g_sessionName); if (ret < 0) { printf("Failed to remove session server!\n"); return; } if (g_sessionCallback != NULL) { free(g_sessionCallback); g_sessionCallback = NULL; } } // 回调函数声明: void onSuccess(int publishId) { printf("publish succeeded, publishId = %d\r\n", publishId); char ipbuff[NSTACKX_MAX_IP_STRING_LEN] = {"0.0.0.0"}; CoapGetIp(ipbuff,NSTACKX_MAX_IP_STRING_LEN,0); printf("CoapGetIp = %s\n",ipbuff); if(StartSessionServer()!=-1) printf("StartSessionServer successed!\n"); } void onFail(int publishId, PublishFailReason reason) { printf("publish failed, publishId = %d, reason = %d\r\n", publishId, reason); } int main(){ // 服务发布接口使用 PublishInfo info = {0}; IPublishCallback cb = {0}; cb.onPublishSuccess = onSuccess; cb.onPublishFail = onFail; char a[] = "456"; info.capabilityData = a; info.capability = "ddmpCapability"; info.dataLen = strlen(a); info.medium = 2; info.publishId = 1; PublishService("cxx", &info, &cb); } ### 3.3.2 编译运行 参考文档: [GCC 编译使用动态链接库和静态链接库的方法](https://developer.aliyun.com/article/12223) 登录后复制 gcc -o publshiServer DemoTest.c -lsoftbus_lite -lrt -lphread  四.源码分析 4.1 总体概述 -------- ### 4.1.1 设备发现 在分布式软总线子系统中,设备分为发现端和被发现端。 * 发现端:请求使用服务的设备。一般指智慧屏设备。 * 被发现端:发布服务的设备。一般指轻量设备。 > 约束:目前必须保证发现端和被发现端处于同一个局域网内。 2. 发现端设备,发起`discover`请求后,使用`coap协议`在局域网内发送广播。报文如下:  5. 被发现端设备使用`PublishService`接口发布服务,接收端收到广播后,发送`coap协议`单播给发现端。报文格式如下:  7. 发现端设备收到报文会更新设备信息。 被发现端发布服务的例子代码如下: > 与上述测试中的代码相似 > >  > > > > 发现的流程图如下: > > > >  ### 4.1.2 数据传输 软总线提供统一的基于`Session`的传输功能,业务可以通过`sessionId`收发数据或获取其相关基本属性。当前本项目只实现被动接收`Session`连接的功能,业务可根据自身需要及`Session`自身属性判断是否接受此`Session`,如不接受,可以主动拒绝此连接。时序图,大致的如下:  * 上面图中`Module`是指使用软总线的任意模块(比如:分布式调度子系统模块),`onPublishServiceDone()`回调函数是在`PushService()`调用中设置的回调函数。 * 在成功发布后,软总线会调用这个回调。然后`Module`可以在这个回调中调用上面代码中的`StartSessionServer()`函数,在`StartSessionServer()`函数中,调用软总线的接口`CreateSessionServer()`创建会话服务,等待其他设备的会话连接。 * 当其他设备会话连接成功后,软总线会首先调用`OnSessionOpenedEventTest()`函数,然后在数据传输完成后调用`OnBytesReceivedTest()`回调函数。`Module`可以在`OnBytesReceivedTest()`中处理数据协议格式的解析以及对于的`Command`命令字的功能调用。 4.2 代码分析 -------- ### 4.2.1 设备发现 `PublishService()`函数的实现在`discovery_service.c`文件中, 这个函数大致可以分成7个部分,下面我们分别分析这个7个部分的代码。  整体流程图如下:  #### ① 权限检查  `SoftBusCheckPermission()`函数实现在`os_adapter`目录中。 为了适配不同的底层操作系统,`os_adapter.c`中封装了一些函数 * source/L0/os\_adapter.c:适配LiteOS  * * 在LiteOS中基本没做权限的判断,只是检查参数是否有效。 * source/L1/os\_adapter.c:适配Linux  * * 增添了`CheckPermission()`函数,使用API来进行权限判断。 #### ② 函数参数有效性校验  第二部分是输出参数有效性检查。输入参数总共是3个,分别是: * moduleName:调用者的模块名称子串 * info:`PublishInfo`结构体,发布的信息 * cb:发布成功或者失败的回调函数 上面的代码可以看到分别对`moduleName`是否为空,子串的长度,`info`里面的`publishId`、`dataLen`等进行了有效性检查。如果有问题,那么会调用 `PublishCallback()`来回调到`cb`里面的失败回调函数,并且给出了出错码。 #### ③ 创建信号量  #### ④ 初始化服务  `InitService()`的代码:  ##### A.是否已经初始化 `g_isServiceInit`全局变量显示是否已经初始化,如果已经被别的模块调用`PublishService()`,那么这个变量的值将为1,那么不需要第二次初始化,直接返回。 ##### B.初始化`Common Manager`(初始化`g_deviceInfo`结构体) `InitCommonManager()`实现如下:   `InitLocalDeviceInfo()`函数主要是把`g_deviceInfo`结构体初始化好。`g_deviceInfo`中几个主要的成员如下: * `deviceName`:对于L0设备为DEV\_L0 * `version`:固定为 “1.0.0” * `deviceId`:通过函数`GetDeviceIdFromFile()`调用取得。这个函数会从`/storage/data/softbus/deviceid`文件中读取,如果读取不到,那么使用随机数字符串组成`deviceId`,然后再写入到上面的文件中。 ##### C.为内部使用的数据结构分配内存 `g_publishModule` 这个全局变量保存所有发布服务的模块的信息数组。这个数组的元素的数据结构如下:  上面的数据结构中的成员内容基本都是从`PublishInfo`结构体来的:  ##### D.注册`wifi Callback` `RegisterWifiCallback()`函数的实现如下:  ##### E.COAP初始化,注册TCP/IP协议栈的处理,注册session的底层socket的处理 在InitService()函数中,调用了CoapInit()函数,代码如下:  深入查看`NSTACKX_Init()`部分如下:  进一步深入`CoapInitDiscovery()`部分,大体分为三个部分:  2. `CoapInitSocket()`  4. `CoapInitSocket()`函数调用了`CoapCreateUdpServer()`函数,创建了一个`UDP`的`socket`,并绑定到`COAP_DEFAULT_PORT`(5684)端口上面上面。这个`socket`赋值给`g_serverFd`,在下面还会使用。  6. `CoapCreateUdpServer()`函数的实现基本上都是用`socket`族的标准接口实现,首先是`socket()`创建一个`socket`,然后用`bind()`绑定到指定的`IP+PORT`。 8. CoapInitWifiEvent()  10. `CoapInitWifiEvent()`函数大致分为两个部分: * `CreateMsgQue()`创建一个消息队列,使用`RegisterWifiEvent()`向`wifi_lite`注册事件回调函数。 * 创建wifi消息队列的处理线程(任务)`CoapWifiEventThread()` 9. CreateCoapListenThread()  11. 12. 创建了一个线程`CoapReadHandle`,用于处理`COAP_DEFAULT_PORT`端口上的`UDP socket`的数据(也就是基于COAP协议的discover广播消息) ##### F.调用CoapWriteMsgQueue()触发获取wifi的IP地址,并启动总线  这个函数就是向wifi的消息队列写入一个消息,强制触发消息回调函数(`WifiEventTrigger()`)的执行。流程图如下:  ##### G.向COAP中注册设备信息  这个函数主要完成g\_localDeviceInfo数据结构的初始化整个InitService的流程图如下:  #### ⑤ 将Publish信息加入到Module列表 `AddPublishModule()`函数,将把`moduleName`和`info`(PublishInfo结构)中的内容加入到`g_publishModule`全局数组中  #### ⑥ 注册COAP服务  #### ⑦ 回调发布成功  调用`PublishCallback()`执行`cb`中的发布成功的回调函数。例如在分布式调度子系统中,使用这个回调函数可以继续进行`session server`的创建。 ### 4.2.2 数据传输 被发现端发布服务后,软总线回调发布成功的函数中,被发现端需要使用`CreateSessionServer()`来创建会话的服务器等待发现端的连接创建会话。 数据传输部分的代码位于`foundation/communication/services/softbus_lite/trans_service`目录中。 整体流程图如下:  #### ① CreateSessionServer() `CreateSessionServer()`函数的实现就在`tcp_session_manager.c`中。函数的代码实现如下:  * `SoftBusCheckPermission()`就是检查权限。 * `GetTcpMgrLock()`和`ReleaseTcpMgrLock()`就是通过`g_sessionManagerLock`这个`Mutex`进行互斥操作,防止同一时间多个模块同时在创建`Session Server`。 真正的业务逻辑在`CreateSessionServerInner()`函数中:  上面SessionListenerMap结构中,最重要的是listener成员,这个成员的结构如下:  其中: * onSessionOpened:是在会话创建时被回调的函数 * onSessionClosed:是在会话结束时被回调的函数 * onBytesReceived:是会话的数据到达的回调函数,注册的模块可以通过这个函数接收会话的报文,按照自己的格式进行解析,并执行会话要求的动作。例如:在分布式调度模块中,接收的数据解析后,可能是START\_FA的命令。 #### ② 处理所有的会话数据接收 在StartBus()函数会调用StartSession()函数创建基于TCP的socket的会话管理服务。这个服务的任务线程是SelectSessionLoop()。  这个线程的主体结构就是一个`while`循环,这个循环只有在`maxFd`为负值的时候才会退出循环。 `maxFd`是`InitSelectList()`函数的返回值,只有出错的情况才会返回负值。 `InitSelectList()`函数就是根据`g_sessionMgr->sessionMap_[]`数组以及`g_sessionMgr->listenFd`构造一个`fd_set`,这个`fd_set`将在下面的`select`中使用。 * g\_sessionMgr->listenFd:就是在`StartBus()`流程里面创建的本地会话服务器的基于`TCP`的`socket`。这个`socket`负责会话的连接请求,所有其他智慧屏设备都是向这个轻量设备侧的`socket`发起连接请求的。 * g\_sessionMgr->sessionMap\_\[\]:这个里面放的是`TcpSession`类型的数组。当连接请求被接受后,本地会生成一个新的`socket`用于数据的传输,这个`socket`就被放在`TcpSession`类型里面。所以`g_sessionMgr->sessionMap_[]`里面放的是所有的已经建立连接的会话的`socket`。 因此,上面的`InitSelectList()`函数得到的是 `ListenFd` + 所有已经建立连接的socket这样一个`fd_set`。那么`select()`函数的功能就是等待这些所有socket上是否有数据发生,如果有数据发生就会往下走去处理数据。 #### ③ 处理数据 处理数据是在`ProcessData()`函数里面,代码如下:  这个函数传入的参数 `tsm`就是 `g_sessionMgr` , `rfds`就是前面 `InitSelectList()`函数得到的 ListenFd + 所有已经建立连接的socket这样一个fd\_set。 `FD_ISSET()`语句就是判断`rfds` 中的`listenFd`是否被置位了,也就是监听连接的socket是否有数据了。 如果有数据就用 `ProcessConnection()`函数去处理连接请求。这个函数里面会在`accept`后新生成一个`socket`,然后构造一个`TcpSession`把新生成用于数据传输的`socket`放在`TcpSession`里面,然后再把`TCPSession`放在`g_sessionMgr->sessionMap_[]`数组里面。当下一次执行`InitSelectList()`的时候,`fd_set`中就会包含这个新建立连接的`socket`了。 最后就是ProcessSessionData()函数的调用。这个函数就是处理已经建立连接的那些会话的数据。  OnProcessDataAvailable()函数的实现如下:  * `GetSessionListenerByName()`函数就是通过`sessionName`从`g_sessionMgr->serverListenerMap[]`数组中找到匹配的`SessionListenerMap`对象。下面调用`TcpSessionRecv()`函数进行数据的接收和解码。 * 当数据接收完成后,就通过`SessionListenerMap`对象中的`onBytesReceived()`回调函数回调给软总线的使用者。 五.参考文档 \[1\] 深圳市奥思网络科技有限公司.源码获取\[EB/OL\]. [https://gitee.com/openharmony/docs/blob/master/get-code/源码获取.md#section1186691118430,2020-12-12](https://gitee.com/openharmony/docs/blob/master/get-code/%E6%BA%90%E7%A0%81%E8%8E%B7%E5%8F%96.md#section1186691118430,2020-12-12). \[2\] 深圳市奥思网络科技有限公司. 分布式通信子系统\[EB/OL\]. [https://gitee.com/openharmony/docs/blob/master/readme/分布式通信子系统README.md,2020-12-12](https://gitee.com/openharmony/docs/blob/master/readme/%E5%88%86%E5%B8%83%E5%BC%8F%E9%80%9A%E4%BF%A1%E5%AD%90%E7%B3%BB%E7%BB%9FREADME.md,2020-12-12). \[3\] 天一涯.GCC 编译使用动态链接库和静态链接库的方法\[EB/OL\]. [https://developer.aliyun.com/article/12223,2015-06-04](https://developer.aliyun.com/article/12223,2015-06-04). \[4\] [https://img1.wsimg.com/blobby/go/bc2bf02b-5e6a-441e-b955-a49c2535530a/downloads/HarmonyOS入门文档\_鸿蒙学堂-0001.pdf?ver=1611125617517](https://img1.wsimg.com/blobby/go/bc2bf02b-5e6a-441e-b955-a49c2535530a/downloads/HarmonyOS%E5%85%A5%E9%97%A8%E6%96%87%E6%A1%A3_%E9%B8%BF%E8%92%99%E5%AD%A6%E5%A0%82-0001.pdf?ver=1611125617517) \[5\] \[6\] \[7\] 我整理的一些关于【软考】的备考学习资料,免费和大家一起分享、学习一下: [https://d.51cto.com/sYneOo](https://d.51cto.com/sYneOo) 本文章为转载内容,我们尊重原作者对文章享有的著作权。如有内容错误或侵权问题,欢迎原作者联系我们进行内容更正或删除文章。
点赞
热门评论
最新评论
匿名用户
+1
-1
·
回复TA
暂无热门评论
相关推荐
阅读更多资讯
热门评论 最新评论
暂无热门评论