跳到主要内容
极客日志极客日志面向AI+效率的开发者社区
首页博客GitHub 精选镜像AI 生图工具UI配色美学隐私政策关于联系
搜索内容 / 工具 / 仓库 / 镜像...⌘K搜索
注册
博客列表
C

DBus 源码剖析:DBusMessage 数据结构

D-Bus 通信基本单元 DBusMessage 由消息头和消息体组成。文章详细解析了消息生命周期(创建、填充、锁定、序列化等)、内部数据结构(引用计数、头信息、体数据、锁定标志、计数器、变更戳等)以及设计原则(不透明类型、引用计数管理、网络格式存储)。通过源码剖析揭示了 D-Bus 消息在进程间通信中的实现机制与内存管理方式。

静心发布于 2026/3/16更新于 2026/7/736 浏览
DBus 源码剖析:DBusMessage 数据结构

DBusMessage 概述和数据结构

1. 概述

DBusMessage 是 D-Bus 通信的基本单元,用于在应用程序之间传递数据。每个消息由两部分组成:

  • 消息头(Header):包含路由信息、消息类型、标志等元数据
  • 消息体(Body):包含实际的数据参数
1.1 消息在 D-Bus 中的作用

D-Bus 是一个进程间通信(IPC)系统,DBusMessage 是通信的基本载体:

  1. 方法调用(Method Call):客户端调用服务端的方法
    • 包含目标服务、对象路径、接口、方法名
    • 包含输入参数
    • 期望收到方法返回或错误消息
  2. 方法返回(Method Return):服务端返回方法调用的结果
    • 包含回复序列号(用于匹配原始方法调用)
    • 包含输出参数或返回值
  3. 信号(Signal):应用程序广播事件通知
    • 不期望回复
    • 可以被多个接收者订阅
    • 用于事件通知和状态变化
  4. 错误(Error):方法调用失败时返回错误信息
    • 包含错误名和错误消息
    • 包含回复序列号(用于匹配原始方法调用)
1.2 消息的生命周期

消息从创建到销毁的完整生命周期:

创建 → 填充 → 锁定 → 序列化 → 传输 → 反序列化 → 使用 → 释放
↓    ↓    ↓    ↓    ↓    ↓    ↓    ↓
new  set  lock marshal send demarshal get unref

详细步骤:

  1. 创建(Creation)
    • 使用 dbus_message_new_* 函数创建
    • 分配内存并初始化结构
    • 引用计数初始化为 1
  2. 填充(Population)
    • 设置头字段(路径、接口、成员等)
    • 添加参数到消息体
    • 可以多次修改
  3. 锁定(Locking)
    • 调用 dbus_message_lock() 锁定消息
    • 锁定后不允许修改
    • 确保网络数据的一致性
  4. 序列化(Marshaling)
    • 转换为网络字节流格式
    • 处理字节序对齐
    • 准备传输
  5. 传输(Transport)
    • 通过 DBusConnection 发送
    • 使用底层传输机制(Unix socket、TCP 等)
  6. 反序列化(Demarshaling)
    • 接收端解析字节流
    • 重建 DBusMessage 结构
  • 验证消息完整性
  • 使用(Usage)
    • 应用程序读取消息内容
    • 处理消息参数
    • 执行相应操作
  • 释放(Destruction)
    • 调用 dbus_message_unref() 减少引用计数
    • 引用计数为 0 时自动释放
    • 清理所有关联资源
  • 2. DBusMessage 数据结构

    2.1 公开接口

    DBusMessage 是一个不透明类型(opaque type),应用程序只能通过 API 函数访问:

    typedef struct DBusMessage DBusMessage;
    

    设计原因:

    • 封装:隐藏内部实现细节
    • 稳定性:允许内部结构变化而不影响 API
    • 安全性:防止应用程序直接修改内部状态
    2.2 内部结构

    实际的 DBusMessage 结构定义在 dbus-message-private.h 中:

    struct DBusMessage {
        DBusAtomic refcount;        /**< 引用计数 */
        DBusHeader header;          /**< 消息头(网络数据和缓存) */
        DBusString body;            /**< 消息体(网络数据) */
        unsigned int locked : 1;    /**< 消息已锁定,不允许修改 */
    #ifndef DBUS_DISABLE_CHECKS
        unsigned int in_cache : 1;  /**< 已在缓存中(调试特性) */
    #endif
        DBusList *counters;         /**< 0-N 个 DBusCounter,用于跟踪消息大小/unix fds */
        long size_counter_delta;    /**< 增加的大小计数器的增量 */
        dbus_uint32_t changed_stamp : CHANGED_STAMP_BITS; /**< 迭代器失效时递增 */
        DBusDataSlotList slot_list; /**< 通过整数 ID 存储的数据 */
    #ifndef DBUS_DISABLE_CHECKS
        int generation;             /**< 消息创建时的 _dbus_current_generation */
    #endif
    #ifdef HAVE_UNIX_FD_PASSING
        int *unix_fds;              /**< 与此消息关联的 Unix 文件描述符 */
        unsigned n_unix_fds;        /**< 数组中有效 fd 的数量 */
        unsigned n_unix_fds_allocated; /**< 数组的分配大小 */
        long unix_fd_counter_delta; /**< unix fd 计数器的增量 */
    #endif
    };
    
    2.3 字段详解
    2.3.1 refcount(引用计数)
    DBusAtomic refcount;
    

    类型:DBusAtomic(原子整数)

    作用:管理消息的生命周期,支持多个引用共享同一消息

    操作:

    • dbus_message_ref():增加引用计数
    • dbus_message_unref():减少引用计数
    • 引用计数为 0 时自动释放消息

    使用场景:

    • 消息需要被多个地方使用
    • 消息需要延迟释放
    • 消息需要传递给回调函数

    示例:

    DBusMessage *msg = dbus_message_new_method_call(...);
    dbus_message_ref(msg); // refcount = 2
    // ... 使用消息
    dbus_message_unref(msg); // refcount = 1
    dbus_message_unref(msg); // refcount = 0, 消息被释放
    
    2.3.2 header(消息头)
    DBusHeader header;
    

    类型:DBusHeader 结构

    作用:存储消息的路由信息和元数据

    内容:

    • 消息类型(METHOD_CALL、METHOD_RETURN、ERROR、SIGNAL)
    • 消息标志(如 NO_REPLY_EXPECTED)
    • 路由信息(路径、接口、成员、目标、发送者)
    • 序列号和回复序列号
    • 消息体类型签名

    存储方式:

    • 使用 DBusString 存储网络字节流格式的数据
    • 包含字段位置缓存(DBusHeaderField 数组)
    • 支持延迟解析和缓存优化
    2.3.3 body(消息体)
    DBusString body;
    

    类型:DBusString(D-Bus 的字节缓冲区)

    作用:存储消息的实际参数数据

    内容:

    • 按照 D-Bus 类型系统序列化的参数
    • 支持基本类型(整数、字符串等)
    • 支持复杂类型(数组、结构体、字典等)

    格式:

    • 使用 D-Bus 的编组(marshaling)格式
    • 8 字节对齐
    • 支持字节序转换
    2.3.4 locked(锁定标志)
    unsigned int locked : 1;
    

    类型:位域(1 位布尔值)

    作用:标记消息是否已锁定,锁定后不允许修改

    锁定时机:

    • 调用 dbus_message_lock() 显式锁定
    • 调用 dbus_connection_send() 发送时自动锁定
    • 调用 dbus_message_marshal() 序列化时自动锁定

    锁定后的限制:

    • 不允许修改头字段
    • 不允许添加或修改参数
    • 不允许删除字段

    设计原因:

    • 确保网络数据的一致性
    • 防止在发送过程中修改消息
    • 支持消息缓存和重用
    2.3.5 in_cache(缓存标志)
    #ifndef DBUS_DISABLE_CHECKS
    unsigned int in_cache : 1;
    #endif
    

    类型:位域(1 位布尔值,仅在调试模式下存在)

    作用:标记消息是否在缓存中(调试特性)

    使用场景:

    • 检测消息是否被意外释放
    • 调试内存管理问题
    • 验证消息生命周期

    注意:仅在 DBUS_DISABLE_CHECKS 未定义时编译

    2.3.6 counters(计数器列表)
    DBusList *counters;
    long size_counter_delta;
    

    类型:

    • counters:DBusList*(链表,每个节点包含一个 DBusCounter*)
    • size_counter_delta:long(消息大小增量)

    作用:跟踪消息的大小和 Unix 文件描述符数量

    DBusCounter 的作用:

    • 跟踪所有活跃消息的总大小
    • 跟踪所有活跃消息的 Unix fd 总数
    • 用于资源限制和监控

    工作原理:

    1. 消息添加到计数器时,增加计数器的值
    2. 消息释放时,减少计数器的值
    3. 计数器可以设置阈值,超过时触发通知

    使用场景:

    • 限制连接的消息大小
    • 监控资源使用
    • 防止内存耗尽

    示例代码:

    // 添加计数器
    _dbus_message_add_counter(message, counter);
    // 消息大小变化时,计数器自动更新
    // size_counter_delta = header.size + body.size
    // 消息释放时,自动减少计数器
    
    2.3.7 changed_stamp(变更戳)
    dbus_uint32_t changed_stamp : CHANGED_STAMP_BITS; // 21 位
    

    类型:位域(21 位无符号整数)

    作用:检测迭代器是否失效

    CHANGED_STAMP_BITS:定义为 21,意味着可以表示 2^21 = 2,097,152 个不同的状态

    工作原理:

    1. 消息创建时,changed_stamp 初始化为某个值
    2. 消息修改时(添加参数、修改字段等),changed_stamp 递增
    3. 迭代器创建时,保存当前的 changed_stamp
    4. 使用迭代器时,检查 changed_stamp 是否匹配
    5. 如果不匹配,说明消息已被修改,迭代器失效

    失效场景:

    • 消息被锁定后修改
    • 消息被复制
    • 消息被序列化/反序列化

    设计原因:

    • 防止使用无效的迭代器
    • 检测并发修改
    • 提供调试信息
    2.3.8 slot_list(数据槽列表)
    DBusDataSlotList slot_list;
    

    类型:DBusDataSlotList(数据槽列表)

    作用:通过整数 ID 存储任意数据

    数据槽机制:

    • 每个消息可以分配多个数据槽
    • 每个数据槽有一个唯一的整数 ID
    • 可以存储任意指针数据
    • 支持设置释放函数

    使用场景:

    • 存储消息相关的上下文信息
    • 实现消息过滤和路由
    • 缓存解析结果
    • 关联用户数据

    API:

    // 分配数据槽
    dbus_message_allocate_data_slot(&slot_id);
    // 设置数据
    dbus_message_set_data(message, slot_id, data, free_func);
    // 获取数据
    void *data = dbus_message_get_data(message, slot_id);
    // 释放数据槽
    dbus_message_free_data_slot(&slot_id);
    
    2.3.9 generation(生成号)
    #ifndef DBUS_DISABLE_CHECKS
    int generation;
    #endif
    

    类型:int(仅在调试模式下存在)

    作用:标记消息创建时的全局生成号

    使用场景:

    • 检测消息是否来自旧的生命周期
    • 调试内存管理问题
    • 验证消息有效性

    注意:仅在 DBUS_DISABLE_CHECKS 未定义时编译

    2.3.10 unix_fds(Unix 文件描述符)
    #ifdef HAVE_UNIX_FD_PASSING
    int *unix_fds;
    unsigned n_unix_fds;
    unsigned n_unix_fds_allocated;
    long unix_fd_counter_delta;
    #endif
    

    类型:

    • unix_fds:int*(文件描述符数组)
    • n_unix_fds:unsigned(有效 fd 数量)
    • n_unix_fds_allocated:unsigned(数组分配大小)
    • unix_fd_counter_delta:long(fd 计数器增量)

    作用:支持通过消息传递 Unix 文件描述符

    生命周期:

    • 添加 fd 时,需要 dup() 文件描述符
    • 消息销毁时,自动关闭所有关联的 fd
    • 传递 fd 时,使用 SCM_RIGHTS 控制消息

    使用场景:

    • 传递文件句柄
    • 传递 socket
    • 传递管道

    限制:

    • 仅在支持 Unix fd 传递的系统上可用
    • 需要特殊的传输机制(Unix socket)
    • 有最大数量限制
    2.4 内存布局

    DBusMessage 结构的内存布局(简化):

    +-------------------+
    | refcount (4/8)    | <- 引用计数(原子整数)
    +-------------------+
    | header            | <- DBusHeader 结构
    | - data            |
    | - DBusString(网络数据)|
    | - fields[11]      |
    | - DBusHeaderField 数组(缓存)|
    | - padding         |
    | - 填充和字节序    |
    | - byte_order      |
    +-------------------+
    | body              | <- DBusString(参数数据)
    +-------------------+
    | locked (1 bit)    | <- 锁定标志
    | in_cache (1 bit)  | <- 缓存标志(调试)
    +-------------------+
    | counters          | <- DBusList*(计数器链表)
    | size_counter_delta| <- long(大小增量)
    +-------------------+
    | changed_stamp     | <- 21 位(变更戳)
    +-------------------+
    | slot_list         | <- DBusDataSlotList(数据槽)
    +-------------------+
    | generation        | <- int(生成号,调试)
    +-------------------+
    | unix_fds          | <- int*(文件描述符数组)
    | n_unix_fds        | <- unsigned(有效数量)
    | n_unix_fds_alloc  | <- unsigned(分配大小)
    | unix_fd_counter   | <- long(fd 计数器增量)
    +-------------------+
    

    大小估算(64 位系统):

    • 基本结构:约 100-200 字节
    • header.data:可变(取决于字段数量)
    • body:可变(取决于参数大小)
    • unix_fds:可变(取决于 fd 数量)
    2.5 字段之间的关系
    2.5.1 header 和 body
    • 分离存储:header 和 body 使用独立的 DBusString
    • 独立管理:可以独立重新分配内存
    • 网络格式:直接使用网络字节流格式,无需转换
    2.5.2 locked 和修改操作
    • 锁定前:可以自由修改 header 和 body
    • 锁定后:所有修改操作都会失败或触发断言
    2.5.3 counters 和资源管理
    • 添加消息:增加计数器的值
    • 释放消息:减少计数器的值
    • 大小跟踪:size_counter_delta 存储消息大小
    2.5.4 changed_stamp 和迭代器
    • 创建迭代器:保存当前的 changed_stamp
    • 修改消息:递增 changed_stamp
    • 使用迭代器:检查 changed_stamp 是否匹配

    3. 设计原则

    3.1 不透明类型
    • 封装:隐藏内部实现细节
    • 稳定性:允许内部结构变化
    • 安全性:防止直接修改
    3.2 引用计数
    • 共享:多个引用可以共享同一消息
    • 自动管理:引用计数为 0 时自动释放
    • 线程安全:使用原子操作
    3.3 网络格式存储
    • 零拷贝:直接使用网络字节流格式
    • 高效:无需格式转换
    • 对齐:支持 8 字节对齐
    3.4 延迟解析
    • 缓存:字段位置缓存
    • 按需解析:只在需要时解析字段
    • 性能优化:避免不必要的解析

    目录

    1. DBusMessage 概述和数据结构
    2. 1. 概述
    3. 1.1 消息在 D-Bus 中的作用
    4. 1.2 消息的生命周期
    5. 2. DBusMessage 数据结构
    6. 2.1 公开接口
    7. 2.2 内部结构
    8. 2.3 字段详解
    9. 2.3.1 refcount(引用计数)
    10. 2.3.2 header(消息头)
    11. 2.3.3 body(消息体)
    12. 2.3.4 locked(锁定标志)
    13. 2.3.5 in_cache(缓存标志)
    14. 2.3.6 counters(计数器列表)
    15. 2.3.7 changed_stamp(变更戳)
    16. 2.3.8 slot_list(数据槽列表)
    17. 2.3.9 generation(生成号)
    18. 2.3.10 unix_fds(Unix 文件描述符)
    19. 2.4 内存布局
    20. 2.5 字段之间的关系
    21. 2.5.1 header 和 body
    22. 2.5.2 locked 和修改操作
    23. 2.5.3 counters 和资源管理
    24. 2.5.4 changed_stamp 和迭代器
    25. 3. 设计原则
    26. 3.1 不透明类型
    27. 3.2 引用计数
    28. 3.3 网络格式存储
    29. 3.4 延迟解析
    • 免费图片AI生成工具免费生成了解详情
    • Magick API 一键接入全球大模型注册送1000万token查看
    • 免费图片视频在线生成30秒,将你的创意变成现实开始设计
    • X/Twitter免费视频下载器免登陆无限额度免费视频解析下载了解详情
    • 100+免费在线小游戏爽一把
    极客日志微信公众号二维码

    微信扫一扫,关注极客日志

    微信公众号「极客日志V2」,在微信中扫描左侧二维码关注。展示文案:极客日志V2 zeeklog

    更多推荐文章

    查看全部
    • 大模型应用开发极简入门:从原理到实战指南
    • Vue3 中点击方法提示不存在的问题排查与解决方案
    • 非科班转行数据分析:Python 自学路径与实战经验
    • RAG 技术为何对下一代 AI 开发至关重要
    • 基于 FPGA 与 W5500 的 SPI 以太网通信实现
    • HarmonyOS NEXT WebView 拉起 H5 页面与权限配置实战
    • AI 大模型开发转行指南:学习路径与求职建议
    • AI 驱动游戏:鸿蒙生态的机会在哪里?
    • 机械臂关节空间轨迹规划的 B 样条算法实现
    • 基于 SpringBoot+Vue 的动漫视频分享与交流平台设计与实现
    • 人工智能:自然语言处理在金融领域的应用与实战
    • 硕士论文盲审前降低AIGC检测率指南
    • 二分查找实战:山峰数组峰顶索引与寻找峰值
    • LeetCode 744. 寻找比目标字母大的最小字母 - 遍历解法
    • 循环神经网络(RNN)与序列数据处理实战
    • LeetCode 27 题:移除元素
    • Java 表达式引擎技术选型分析:SpEL 与 QLExpress
    • llama.cpp 大模型部署指南:CPU/GPU 全兼容与 Docker 快速启动
    • 基于 SpringBoot+Vue 的生鲜交易系统设计与实现
    • 语言模型基础:本地部署开源大模型实战

    相关免费在线工具

    • Base64 字符串编码/解码

      将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online

    • Base64 文件转换器

      将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online

    • Markdown转HTML

      将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML转Markdown 互为补充。 在线工具,Markdown转HTML在线工具,online

    • HTML转Markdown

      将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML转Markdown在线工具,online

    • JSON 压缩

      通过删除不必要的空白来缩小和压缩JSON。 在线工具,JSON 压缩在线工具,online

    • JSON美化和格式化

      将JSON字符串修饰为友好的可读格式。 在线工具,JSON美化和格式化在线工具,online