鸿蒙OpenHarmony源码分析之分布式软总线:trans_service模块(1)/认证通道管理

📌往期推文全新看点(文中附带最新·鸿蒙全栈学习笔记)

①📖 鸿蒙应用开发与鸿蒙系统开发哪个更有前景?

②📖嵌入式开发适不适合做鸿蒙南向开发?看完这篇你就了解了~

③📖 对于大前端开发来说,转鸿蒙开发究竟是福还是祸?

④📖 鸿蒙岗位需求突增!移动端、PC端、IoT到底该怎么选?

⑤📖 记录一场鸿蒙开发岗位面试经历~

⑥📖 持续更新中……


一、 概述

trans_service模块基于系统内核提供的socket通信,向authmanager模块提供设备认证通道管理和设备认证数据的传输;向业务模块提供session管理和基于session的数据收发功能,并且通过GCM模块的加密功能提供收发报文的加解密保护。

二、 源码分析

  1. 入口函数为StartListener(),主要是针对Linux系统内核,其它系统之后会有补充,解析如下
/*
函数功能: 启动监听其他设备的连接请求或者新数据响应
函数参数:callback  回调函数的地址;ip  需要绑定的server端ip地址
函数返回值:返回建立TCP连接的套接字的port
详细:监听器的主要作用是监听新连接请求和已建立连接的数据通信。
    1.首先作为server端产生监听套接字fd,然后绑定端口和IP,这里的端口绑定采用了动态分配的方式。
    2.然后创建子线程执行监听任务,采用的是select的io复用方式来处理并发请求。
*/
int StartListener(BaseListener *callback, const char *ip)
{
    if (callback == NULL || ip == NULL) {
        return -DBE_BAD_PARAM;
    }
    g_callback = callback;
    int rc = InitListenFd(ip, SESSIONPORT);//产生并初始化监听描述符,传入的SESSIONPORT为0,绑定0端口号的意义在于动态选取本地可用端口号,不用考虑端口重用的问题
    if (rc != DBE_SUCCESS) {
        return -DBE_BAD_PARAM;
    }
    signal(SIGPIPE, SIG_IGN);//捕获SIGPIPE信号,SIG_IGN表示忽视该信号,不执行SIGPIPE默认操作:终止程序
    ThreadAttr attr = {"auth", 0x800, 20, 0, 0};//初始化线程属性,"auth"为线程名,线程栈大小为0x800 | MIN_STACK_SIZE,单位为字节,线程优先级为20
    register ThreadId threadId = (ThreadId)AuthCreate((Runnable)WaitProcess, &attr);//创建子线程进行监听任务,包括设备认证过程中的新连接或者新数据
    if (threadId == NULL) {//创建子线程失败,则返回-1
        SOFTBUS_PRINT("[TRANS] StartListener AuthCreate fail\n");
        return -1;
    }
    return GetSockPort(g_listenFd);//返回建立TCP连接的套接字的port,因为这里绑定的端口是0,其实是内核随机分配的端口号
}
  1. 调用InitListenFd()函数产生并初始化监听套接字fd
/*
函数功能: 产生并初始化监听描述符
函数参数:ip    server端IP地址;port    server端端口
函数返回值:成功返回0,失败返回错误码
详细:
*/
static int InitListenFd(const char *ip, int port)//
{
    if (ip == NULL || g_listenFd != -1) {
        return -DBE_BAD_PARAM;
    }
    if (strncmp(ip, "0.0.0.0", strlen(ip)) == 0) {//如果输入ip为0.0.0.0,则返回错误码
        return -DBE_BAD_PARAM;
    }
    int rc = OpenTcpServer(ip, port);//初始化server端套接字,生成监听fd
    if (rc < 0) {
        SOFTBUS_PRINT("[TRANS] InitListenFd OpenTcpServer fail\n");
        return rc;
    }
    g_listenFd = rc;
    RefreshMaxFd(g_listenFd);//更新最大描述符值,因为后续需要为select函数提供最大描述符值,select函数需要获得监听集合中所有文件描述符的范围
    rc = listen(rc, DEFAULT_BACKLOG);//将该fd从CLOSED转换到LISTEN状态,监听client端(主动端)发起的连接信息
    if (rc != 0) {
        SOFTBUS_PRINT("[TRANS] InitListenFd listen fail\n");
        StopListener();
        return -DBE_LISTEN_FAIL;
    }
    return DBE_SUCCESS;
}
  1. OpenTcpServer()函数
/*
函数功能: 初始化server端套接字,绑定ip地址及port
函数参数:ip    需要进行绑定的ip地址;port  需要进行绑定的port
函数返回值:成功返回生成的套接字描述符,失败返回错误码
详细:
*/
int OpenTcpServer(const char *ip, uint16_t port)
{
    if (ip == NULL) {
        return -DBE_BAD_PARAM;
    }
    struct sockaddr_in addr = {0};
    errno = 0;
    int rc = inet_pton(AF_INET, ip, &addr.sin_addr);//将点分十进制的ip字符串转化为网络字节序的32位ip地址
    if (rc <= 0) {
        return -DBE_BAD_IP;
    }
    addr.sin_family = AF_INET;//ipv4
    addr.sin_port = htons(port);//网络字节序的port
    errno = 0;
    int fd = socket(AF_INET, SOCK_STREAM, 0);//生成基于TCP协议的套接字描述符
    if (fd < 0) {
        return -DBE_OPEN_SOCKET;
    }
    SetServerOption(fd);//设置套接字选项,地址可重用和禁用Nagle算法
    errno = 0;
    rc = bind(fd, (struct sockaddr *)&addr, sizeof(addr));//绑定server端IP地址和port
    if (rc < 0) {
        ShutDown(fd);
        return -DBE_BIND_SOCKET;
    }
    return fd;
}
  1. 创建线程用于设备身份认证:AuthCreate()函数
/*
函数功能: 初始化用于身份验证的线程相关属性并创建线程
函数参数:run   子线程回调函数;attr    线程属性结构体地址
函数返回值:线程id
详细:
*/
ThreadId AuthCreate(Runnable run, const ThreadAttr *attr)
{
    pthread_attr_t threadAttr;
    pthread_attr_init(&threadAttr);//初始化一个线程属性对象threadAttr
    pthread_attr_setstacksize(&threadAttr, (attr->stackSize | MIN_STACK_SIZE));//设置线程的栈大小
    struct sched_param sched = {attr->priority};
    pthread_attr_setschedparam(&threadAttr, &sched);//设置线程调度优先级
    pthread_key_create(&g_localKey, NULL);//创建线程私有的全局数据(TSD),同名而地址不同
    pthread_t threadId = 0;
    int errCode = pthread_create(&threadId, &threadAttr, run, NULL);//创建线程
    if (errCode != 0) {
        return NULL;
    }
    return (ThreadId)threadId;//返回void * 类型的线程id
}
  1. 执行线程回调函数WaitProcess()
/*
函数功能: 使用忙等方式,调用select()来监听listenFd和数据g_dataFd的信息,如果监听到有数据可读,则进入ProcessAuthData来处理
函数参数:无
函数返回值:无
详细:
*/
static void WaitProcess(void)
{
    SOFTBUS_PRINT("[TRANS] WaitProcess begin\n");
    fd_set readSet;//可读描述符fd集合
    fd_set exceptfds;//异常描述符fd集合
    while (1) {//轮询监听可读事件或者异常事件的变化
        /*每次调用select前都要重新设置文件描述符和时间,因为事件发生后,文件描述符和时间都被内核修改*/
        FD_ZERO(&readSet);//清空描述符集合
        FD_ZERO(&exceptfds);
        FD_SET(g_listenFd, &readSet);//将监听fd添加到可读集合中
        if (g_dataFd >= 0) {//如果通信描述符存在,将通信描述符添加至可读集合和异常集合中
            FD_SET(g_dataFd, &readSet);
            FD_SET(g_dataFd, &exceptfds);
        }
        int ret = select(g_maxFd + 1, &readSet, NULL, &exceptfds, NULL);//开始监听readSet和exceptfds
        if (ret > 0) {//ret大于0表示监听的集合中有ret个描述符状态发生改变
            if (!ProcessAuthData(g_listenFd, &readSet)) {//处理接收到的认证数据
                SOFTBUS_PRINT("[TRANS] WaitProcess ProcessAuthData fail\n");
                StopListener();//关闭监听器
                break;
            }
        } else if (ret < 0) {//发生错误
            if (errno == EINTR || (g_dataFd > 0 && FD_ISSET(g_dataFd, &exceptfds))) {//产生中断或者异常
                SOFTBUS_PRINT("[TRANS] errno == EINTR or g_dataFd is in exceptfds set.\n");
                CloseAuthSessionFd(g_dataFd);//关闭认证会话的连接
                continue;
            }
            SOFTBUS_PRINT("[TRANS] WaitProcess select fail, stop listener\n");
            StopListener();//关闭监听器
            break;
        }
    }
}
  1. ProcessAuthData()函数
/*
函数功能: 处理listenFd的事件调用accept建立连接生成通信描述符g_dataFd,或者处理g_dataFd的通信事件
函数参数:监听描述符listenFd,可读描述符集合
函数返回值:成功返回true,失败返回false
详细:
*/
static bool ProcessAuthData(int listenFd, const fd_set *readSet)
{
    if (readSet == NULL || g_callback == NULL || g_callback->onConnectEvent == NULL ||
        g_callback->onDataEvent == NULL) {
        return false;
    }
    if (FD_ISSET(listenFd, readSet)) {//如果有设备发起连接,响应listenFd事件,accept建立socket连接,然后调用回调函数onConnectEvent处理连接事件
        struct sockaddr_in addrClient = {0};
        socklen_t addrLen = sizeof(addrClient);
        g_dataFd = accept(listenFd, (struct sockaddr *)(&addrClient), &addrLen);//建立socket连接
        if (g_dataFd < 0) {//accept函数执行出错
            CloseAuthSessionFd(listenFd);
            return false;
        }
        RefreshMaxFd(g_dataFd);//更新最大描述符值,因为后续需要为select函数提供最大描述符值,select函数需要获得监听集合中所有文件描述符的范围
        if (g_callback->onConnectEvent(g_dataFd, inet_ntoa(addrClient.sin_addr)) != 0) {//响应连接事件
            CloseAuthSessionFd(g_dataFd);
        }
    }
    if (g_dataFd > 0 && FD_ISSET(g_dataFd, readSet)) {//如果接收到设备发送的可读数据,响应g_dataFd的事件,调用回调函数onDataEvent处理数据传输事件
        g_callback->onDataEvent(g_dataFd);//响应通信事件
    }
    return true;
}

至此,trans_service模块为认证模块提供了认证通道管理和认证数据的收发,具体的认证过程及具体的认证协议在authmanager模块实现。

<think>嗯,用户现在遇到了编译错误,提示找不到boost/assign.hpp这个头文件。我需要帮他们解决这个问题。首先,我应该回忆一下常见的导致这种错误的原因。通常来说,这种错误是因为编译器找不到对应的头文件路径,也就是Boost库没有被正确安装或者CMake配置中没有包含Boost的头文件路径。 用户使用的是MinGW,系统是Windows环境,所以可能需要指导他们如何安装Boost库,并配置CMakeLists.txt。用户之前的问题是关于pybind11的配置,现在转向Boost库的问题,可能他们的项目同时依赖这两个库。我需要分步骤引导他们解决这个问题。 首先,我应该确认用户是否已经安装了Boost库。如果没有安装,他们需要先安装Boost。在Windows下,使用MinGW安装Boost可能有几种方法:比如使用预编译的二进制包,或者从源代码编译。不过对于新手来说,可能更简单的方法是通过MSYS2或者vcpkg这样的包管理器安装,但用户可能没有这些工具,所以需要给出通用的安装方法。 其次,安装完成后,用户需要在CMakeLists.txt中添加Boost的查找和链接。这时候需要使用find_package来定位Boost,并包含头文件路径和链接库。用户可能没有在CMake中正确配置这些步骤,导致编译时找不到头文件。 另外,用户可能没有设置BOOST_ROOT环境变量,或者CMake没有正确找到Boost的安装路径。这时候需要指导用户如何设置这些变量,或者在CMake命令中指定Boost的路径。 还要注意Boost的版本是否兼容,以及用户是否安装了正确的组件。例如,有些Boost库是头文件库,只需要包含头文件,而有些则需要链接动态库。assign.hpp属于Boost.Assign库,这个库是头文件库,所以用户可能只需要正确包含头文件路径,而不需要链接库。但需要确认这一点,避免用户遗漏其他依赖。 可能的解决方案步骤包括: 1. 安装Boost库,确保头文件路径正确。 2. 在CMakeLists.txt中使用find_package(Boost REQUIRED)来查找Boost。 3. 包含Boost的头文件目录,使用include_directories或target_include_directories。 4. 如果使用了需要链接的Boost库,还需要target_link_libraries。 另外,用户可能在安装Boost时选择了错误的架构(比如32位和64位的MinGW不匹配),需要确认安装的Boost版本是否与编译器兼容。例如,如果用户用的是MinGW-w64 64位,那么Boost也需要编译成64位的版本。 用户的具体错误信息显示在trans_map.cpp中包含了boost/assign.hpp,而编译器找不到这个文件。这说明Boost的头文件路径没有被正确包含到编译器的搜索路径中。因此,解决的关键在于确保CMake能够找到Boost的安装位置,并将该路径传递给编译器。 可能需要指导用户如何手动指定Boost的路径,比如通过设置BOOST_ROOT变量或者在CMake命令中传递参数,例如-DBOOST_ROOT=D:/boost。 总结一下,我需要逐步引导用户检查Boost的安装情况,确认CMake配置是否正确,并根据他们的具体情况提供不同的解决方案,比如使用vcpkg安装、手动安装并配置路径,或者修改CMakeLists文件。同时,要提醒用户注意路径中的空格问题,因为用户的路径中有“Map convert tool”这样的目录名,可能需要用引号包裹路径,或者在CMake中正确处理空格。</think>--- ### 问题分析 您遇到的编译错误核心问题是 **Boost 库的头文件未被正确找到**,具体表现为: ```bash fatal error: boost/assign.hpp: No such file or directory ``` 这说明: 1. Boost 库未安装 2. 或 CMake 未正确配置 Boost 库路径 --- ### 解决方案步骤 #### 步骤1:安装 Boost 库 根据您的编译环境(Windows + MinGW),推荐以下安装方式: ##### 方法1:通过 MSYS2 安装(推荐) ```bash # 在 MSYS2 终端中执行 pacman -S mingw-w64-x86_64-boost ``` 安装路径通常为:`/mingw64/include/boost` ##### 方法2:手动安装 1. 下载预编译包:从 [Boost 官网](https://www.boost.org/users/download/) 选择 `Prebuilt Windows binaries` 2. 选择与 MinGW 匹配的版本(如 `boost_1_84_0-msvc-14.3-64.exe`) 3. 安装到无空格路径(如 `D:\libs\boost_1_84_0`) --- #### 步骤2:配置 CMakeLists.txt 修改您的 `CMakeLists.txt`,添加 Boost 依赖: ```cmake cmake_minimum_required(VERSION 3.5) project(YourProject) # 关键配置:指定 Boost 路径(根据实际安装路径修改) set(BOOST_ROOT "D:/libs/boost_1_84_0") # 或通过环境变量设置 # 查找 Boost 库 find_package(Boost 1.84.0 REQUIRED COMPONENTS system filesystem) # 按需添加组件 # 包含头文件路径 include_directories(${Boost_INCLUDE_DIRS}) # 链接到目标 add_executable(trans_map src/trans_map.cpp) target_link_libraries(trans_map PRIVATE ${Boost_LIBRARIES}) ``` --- #### 步骤3:验证路径配置 通过 CMake 命令显式指定路径(如果步骤2未生效): ```bash cmake -DBOOST_ROOT="D:/libs/boost_1_84_0" -B build ``` --- ### 关键注意事项 1. **路径规范**: - Windows 路径使用正斜杠 `/` 或双反斜杠 `\\` - 避免路径包含中文或空格(您的当前路径 `Map convert tool` 含空格,建议改为 `MapConvertTool`) 2. **版本匹配**: - MinGW 编译器位数(32/64位)必须与 Boost 版本一致 - 通过 `g++ -v` 查看编译器信息 3. **最小化依赖**: - `boost/assign.hpp` 是纯头文件库,只需包含路径,无需链接二进制库 --- ### 验证安装成功的标志 1. 在编译输出中应出现: ```bash -- Found Boost: D:/libs/boost_1_84_0 (found suitable version "1.84.0") ``` 2. 头文件可被正确找到: ```bash ls D:/libs/boost_1_84_0/boost/assign.hpp ``` --- ### 常见问题排查表 | 现象 | 解决方案 | |-------|---------| | `undefined reference to boost::...` | 添加 `COMPONENTS` 并确保已编译对应库 | | `Invalid CMake command: find_package` | 检查 CMake 版本是否 ≥3.5 | | 路径包含空格 | 使用短路径(如 `D:/PROGRA~1/boost`)或迁移项目 | | MinGW 工具链不匹配 | 通过 `pacman -S mingw-w64-x86_64-toolchain` 安装完整工具链 | 建议优先使用 MSYS2 管理依赖,可避免大多数路径问题。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值