常用数据结构
在 GDBus(基于 D-Bus 的通信框架)中,最常用的数据类型主要是通过 GVariant 来表示的。GVariant 是 GLib 提供的一种用于存储任意复杂数据结构的容器类型,它支持多种基础数据类型以及嵌套结构。以下是 GDBus 中最常用的一些数据类型及其对应的 D-Bus 类型代码:
基础数据类型
-
BYTE (
y
)- GLib 数据类型 :
guchar
- 描述: 无符号8位整数 (0-255)
- GLib 数据类型 :
-
BOOLEAN (
b
)- GLib 数据类型 :
gboolean
- 描述 : 布尔值,通常为
TRUE
或FALSE
- GLib 数据类型 :
-
INT16 (
n
)- GLib 数据类型 :
gint16
- 描述: 有符号16位整数 (-32768到32767)
- GLib 数据类型 :
-
UINT16 (
q
)- GLib 数据类型 :
guint16
- 描述: 无符号16位整数 (0到65535)
- GLib 数据类型 :
-
INT32 (
i
)- GLib 数据类型 :
gint32
- 描述: 有符号32位整数 (-2^31 到 2^31 - 1)
- GLib 数据类型 :
-
UINT32 (
u
)- GLib 数据类型 :
guint32
- 描述: 无符号32位整数 (0到4294967295)
- GLib 数据类型 :
-
INT64 (
x
)- GLib 数据类型 :
gint64
- 描述: 有符号64位整数
- GLib 数据类型 :
-
UINT64 (
t
)- GLib 数据类型 :
guint64
- 描述: 无符号64位整数
- GLib 数据类型 :
-
DOUBLE (
d
)- GLib 数据类型 :
gdouble
- 描述: 双精度浮点数
- GLib 数据类型 :
-
STRING (
s
)- GLib 数据类型 :
gchar*
- 描述: UTF-8 编码的字符串
- GLib 数据类型 :
复杂数据类型
-
ARRAY (
a
)- 示例 :
ai
表示一个整数数组 - 描述: 包含相同类型的元素集合
- 示例 :
-
VARIANT (
v
)- 描述: 可以包含任何其他类型的变体值
-
DICTIONARY (
a{sv}
或a{ss}
等)- 示例 :
a{ss}
表示键和值都是字符串的字典 - 描述: 键值对的集合,其中键通常是字符串,值可以是任意类型
- 示例 :
-
STRUCTURE (
r
或括号形式如(ii)
)- 示例 :
(is)
表示一个整数和一个字符串组成的结构 - 描述: 固定顺序的多个值的组合
- 示例 :
示例
创建一个简单的 GVariant
c
// 创建一个 INT32 类型的 GVariant
GVariant *variant = g_variant_new_int32(42);
// 创建一个 STRING 类型的 GVariant
GVariant *string_variant = g_variant_new_string("Hello, World!");
// 创建一个 ARRAY 类型的 GVariant
GVariantBuilder builder;
g_variant_builder_init(&builder, G_VARIANT_TYPE_ARRAY);
g_variant_builder_add(&builder, "i", 1);
g_variant_builder_add(&builder, "i", 2);
g_variant_builder_add(&builder, "i", 3);
GVariant *array_variant = g_variant_builder_end(&builder);
使用 GVariant 在 D-Bus 方法调用中传递参数
假设你有一个 D-Bus 接口方法 AddNumbers
需要接收两个整数并返回它们的和:
xml
<method name="AddNumbers">
<arg type="i" name="num1" direction="in"/>
<arg type="i" name="num2" direction="in"/>
<arg type="i" name="sum" direction="out"/>
</method>
你可以这样实现客户端调用:
c
gint num1 = 5, num2 = 7;
gint sum;
com_example_calculator_call_add_numbers_sync(proxy, num1, num2, &sum, NULL, &error);
if (!error) {
g_print("Sum: %d\n", sum);
}
而在服务端处理该方法时,可以通过 GVariant 获取输入参数,并设置输出参数:
c
static void handle_add_numbers(ComExampleCalculator *object, GDBusMethodInvocation *invocation, gint num1, gint num2) {
gint sum = num1 + num2;
com_example_calculator_complete_add_numbers(object, invocation, sum);
}
常用库函数
在使用 GDBus 进行开发时,有几个关键的库函数和工具是经常使用的。这些函数主要用于创建和管理 D-Bus 连接、注册对象、调用远程方法、处理信号等。以下是一些最常用的 GDBus 库函数及其简要说明:
1. 建立连接
-
g_bus_get_sync()
: 同步获取一个 D-Bus 连接。cGDBusConnection *connection = g_bus_get_sync(G_BUS_TYPE_SESSION, NULL, &error);
G_BUS_TYPE_SESSION
: 表示会话总线。NULL
: 取消操作的上下文(Cancellable)。&error
: 错误信息。
2. 注册对象到 D-Bus 上
-
g_dbus_interface_skeleton_export()
: 将接口骨架导出到 D-Bus 上。cgboolean success = g_dbus_interface_skeleton_export(G_DBUS_INTERFACE_SKELETON(service), connection, "/com/example/calculator", &error);
G_DBUS_INTERFACE_SKELETON(service)
: 要导出的服务实例。connection
: D-Bus 连接。"/com/example/calculator"
: 对象路径。&error
: 错误信息。
3. 创建代理对象
-
com_example_calculator_proxy_new_sync()
: 创建一个新的代理对象,用于与远程服务进行通信。cComExampleCalculator *proxy = com_example_calculator_proxy_new_sync(connection, G_DBUS_PROXY_FLAGS_NONE, "com.example.Calculator", "/com/example/calculator", NULL, &error);
4. 调用远程方法
-
com_example_calculator_call_add_numbers_sync()
: 同步调用远程方法。cgboolean success = com_example_calculator_call_add_numbers_sync(proxy, num1, num2, &result, NULL, &error);
proxy
: 代理对象。num1
,num2
: 输入参数。&result
: 输出结果。NULL
: 取消操作的上下文(Cancellable)。&error
: 错误信息。
5. 发送信号
-
com_example_calculator_emit_status_update()
: 发送信号通知客户端。ccom_example_calculator_emit_status_update(object, "Calculation completed.");
6. 处理信号
-
g_signal_connect()
: 连接信号处理函数。cg_signal_connect(proxy, "status-update", G_CALLBACK(on_status_update), NULL);
proxy
: 代理对象。"status-update"
: 信号名称。G_CALLBACK(on_status_update)
: 回调函数。NULL
: 用户数据。
7. 使用 GVariant 构建复杂数据结构
-
g_variant_builder_new()
: 创建一个新的变体构建器。cGVariantBuilder *builder = g_variant_builder_new(G_VARIANT_TYPE("av"));
G_VARIANT_TYPE("av")
: 指定构建器类型为数组(a
)中的变体(v
)。
-
g_variant_builder_add()
: 添加元素到构建器中。cg_variant_builder_add(builder, "{ss}", "location", "file:///tmp/00000001/1.mp3");
-
g_variant_builder_end()
: 完成构建并生成 GVariant 对象。cGVariant *playlist = g_variant_builder_end(builder);
8. 序列化与反序列化
-
g_variant_new_from_data()
: 根据二进制数据创建 GVariant 对象。cGVariant *playlist = g_variant_new_from_data(G_VARIANT_TYPE("av"), data, size, TRUE, NULL, NULL);
G_VARIANT_TYPE("av")
: 数据类型。data
: 二进制数据。size
: 数据大小。TRUE
: 是否信任数据来源。
-
g_variant_iter_new()
: 创建一个新的迭代器用于遍历 GVariant 数组。cGVariantIter *iter = g_variant_iter_new(playlist);
-
g_variant_iter_next()
: 遍历 GVariant 数组中的下一个元素。cwhile (g_variant_iter_next(iter, "v", &item)) { // 处理每个 item }