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

DBus 源码剖析:DBusMessage 数据结构

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

静心发布于 2026/3/16更新于 2026/10/1691 浏览
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 延迟解析

    更多推荐文章

    查看全部
    • DBeaver 社区版 AI 助手配置指南
    • DBeaver 配置本地 MySQL 驱动文件
    • Mac Mini M4 本地 AI 模型部署指南:从 Ollama 到 Stable Diffusion
    • 基于 OpenClaw 与飞书集成构建 AI 新闻推送机器人
    • Vivado RAM IP 核配置与读写时序仿真
    • 基于 OpenClaw + 飞书实现 AI 新闻推送机器人
    • Python Mode for Processing 创意编程使用指南
    • Opencode:自带沙箱的开源代码解释器,赋能 DeepSeek 本地编程
    • DataX 二进制与源码部署及 DataX-Web 可视化平台搭建
    • 微信小程序 WebView 组件使用指南与常见应用场景
    • ComfyUI 节点式 AI 绘画工作流核心解析
    • 海南超级AI医院:自贸港背景下的数智医疗标杆
    • DankDroneDownloader 无人机固件管理工具技术解析
    • 6 款主流 AI 检测降重工具实测对比与选择建议
    • JDK 1.8 在 Windows 系统下的安装与配置教程
    • 论文解读:使用人类反馈训练语言模型遵循指令
    • Ubuntu 22.04 网络配置实战:静态 IP 与 DNS 设置
    • llama.cpp 简介:本地高效运行大语言模型的推理框架
    • Vanna:基于 RAG 的自然语言对话 SQL 数据库框架
    • 基于 Ollama 在本地电脑部署和运行大语言模型指南

    相关免费在线工具

    • 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