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

DBusMessage 是 D-Bus 通信的基本单元,用于在应用程序之间传递数据。每个消息由两部分组成:
D-Bus 是一个进程间通信(IPC)系统,DBusMessage 是通信的基本载体:
消息从创建到销毁的完整生命周期:
创建 → 填充 → 锁定 → 序列化 → 传输 → 反序列化 → 使用 → 释放
↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓
new set lock marshal send demarshal get unref
详细步骤:
dbus_message_new_* 函数创建dbus_message_lock() 锁定消息DBusConnection 发送DBusMessage 结构dbus_message_unref() 减少引用计数DBusMessage 是一个不透明类型(opaque type),应用程序只能通过 API 函数访问:
typedef struct DBusMessage DBusMessage;
设计原因:
实际的 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
};
DBusAtomic refcount;
类型:DBusAtomic(原子整数)
作用:管理消息的生命周期,支持多个引用共享同一消息
操作:
dbus_message_ref():增加引用计数dbus_message_unref():减少引用计数使用场景:
示例:
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, 消息被释放
DBusHeader header;
类型:DBusHeader 结构
作用:存储消息的路由信息和元数据
内容:
存储方式:
DBusString 存储网络字节流格式的数据DBusHeaderField 数组)DBusString body;
类型:DBusString(D-Bus 的字节缓冲区)
作用:存储消息的实际参数数据
内容:
格式:
unsigned int locked : 1;
类型:位域(1 位布尔值)
作用:标记消息是否已锁定,锁定后不允许修改
锁定时机:
dbus_message_lock() 显式锁定dbus_connection_send() 发送时自动锁定dbus_message_marshal() 序列化时自动锁定锁定后的限制:
设计原因:
#ifndef DBUS_DISABLE_CHECKS
unsigned int in_cache : 1;
#endif
类型:位域(1 位布尔值,仅在调试模式下存在)
作用:标记消息是否在缓存中(调试特性)
使用场景:
注意:仅在 DBUS_DISABLE_CHECKS 未定义时编译
DBusList *counters;
long size_counter_delta;
类型:
counters:DBusList*(链表,每个节点包含一个 DBusCounter*)size_counter_delta:long(消息大小增量)作用:跟踪消息的大小和 Unix 文件描述符数量
DBusCounter 的作用:
工作原理:
使用场景:
示例代码:
// 添加计数器
_dbus_message_add_counter(message, counter);
// 消息大小变化时,计数器自动更新
// size_counter_delta = header.size + body.size
// 消息释放时,自动减少计数器
dbus_uint32_t changed_stamp : CHANGED_STAMP_BITS; // 21 位
类型:位域(21 位无符号整数)
作用:检测迭代器是否失效
CHANGED_STAMP_BITS:定义为 21,意味着可以表示 2^21 = 2,097,152 个不同的状态
工作原理:
changed_stamp 初始化为某个值changed_stamp 递增changed_stampchanged_stamp 是否匹配失效场景:
设计原因:
DBusDataSlotList slot_list;
类型:DBusDataSlotList(数据槽列表)
作用:通过整数 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);
#ifndef DBUS_DISABLE_CHECKS
int generation;
#endif
类型:int(仅在调试模式下存在)
作用:标记消息创建时的全局生成号
使用场景:
注意:仅在 DBUS_DISABLE_CHECKS 未定义时编译
#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 文件描述符
生命周期:
dup() 文件描述符SCM_RIGHTS 控制消息使用场景:
限制:
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 位系统):
DBusStringsize_counter_delta 存储消息大小changed_stampchanged_stampchanged_stamp 是否匹配
微信公众号「极客日志」,在微信中扫描左侧二维码关注。展示文案:极客日志 zeeklog
将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online
将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online
将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML转Markdown 互为补充。 在线工具,Markdown转HTML在线工具,online
将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML转Markdown在线工具,online
通过删除不必要的空白来缩小和压缩JSON。 在线工具,JSON 压缩在线工具,online
将JSON字符串修饰为友好的可读格式。 在线工具,JSON美化和格式化在线工具,online