使用GLib D-Bus 库创建dbus服务端
结合:使用GLib D-Bus 库创建dbus客户端-CSDN博客
函数g_dbus_node_info_new_for_xml的用法
g_dbus_node_info_new_for_xml
是 GLib 中用于解析 D-Bus 接口描述 XML 并生成 GDBusNodeInfo
对象的函数,其核心功能是将 XML 格式的接口定义转换为程序可操作的结构化数据。以下是详细用法说明:
函数原型
GDBusNodeInfo *g_dbus_node_info_new_for_xml (const gchar *xml_data, GError **error);
参数说明
-
xml_data
- 类型:
const gchar*
- 作用:传入符合 D-Bus 接口描述的 XML 字符串。
- 格式要求:需包含完整的
<node>
和<interface>
定义,例如:<node><interface name="org.example.MyInterface"><method name="ExampleMethod"><arg type="s" name="input" direction="in"/><arg type="i" name="output" direction="out"/></method></interface> </node>
- 类型:
-
error
- 类型:
GError**
- 作用:捕获解析过程中的错误(如 XML 格式无效或接口定义冲突)。
- 若解析失败,函数返回
NULL
并通过此参数返回错误详情。
- 类型:
返回值
- 成功时返回
GDBusNodeInfo*
对象,包含解析后的接口、方法、信号和属性信息。 - 需通过
g_dbus_node_info_unref()
释放内存以避免泄漏。
典型用法示例
-
定义 XML 接口描述
静态字符串或从文件加载均可:static const gchar introspection_xml[] ="<node>"" <interface name='org.example.Test'>"" <method name='Echo'>"" <arg type='s' name='input' direction='in'/>"" <arg type='s' name='output' direction='out'/>"" </method>"" </interface>""</node>";
-
解析并注册接口
GError *error = NULL; GDBusNodeInfo *info = g_dbus_node_info_new_for_xml(introspection_xml, &error); if (info == NULL) {g_printerr("解析失败: %s\n", error->message);g_error_free(error);return; }
-
使用解析结果
- 通过
info->interfaces
访问接口列表。 - 结合
g_dbus_connection_register_object()
将接口注册到 D-Bus 总线上。
- 通过
注意事项
- 线程安全:需在 GLib 主循环线程中调用。
- XML 校验:需确保 XML 符合 D-Bus 规范,否则可能返回错误。
- 生命周期管理:返回的
GDBusNodeInfo
对象需手动释放。
函数g_dbus_node_info_lookup_interface的用法
g_dbus_node_info_lookup_interface
是 GLib 中用于从已解析的 D-Bus 节点信息中查找特定接口的函数,其核心功能是通过接口名称快速定位接口定义。以下是详细说明:
函数原型
GDBusInterfaceInfo *g_dbus_node_info_lookup_interface (GDBusNodeInfo *info,const gchar *interface_name
);
参数说明
-
info
- 类型:
GDBusNodeInfo*
- 作用:指向通过
g_dbus_node_info_new_for_xml
解析得到的节点信息对象。 - 要求:必须为非
NULL
的有效对象,否则行为未定义。
- 类型:
-
interface_name
- 类型:
const gchar*
- 作用:需查找的接口名称(如
"org.example.MyInterface"
)。 - 注意:名称需与 XML 定义中的接口名完全匹配(区分大小写)。
- 类型:
返回值
- 成功:返回指向
GDBusInterfaceInfo
的指针,包含接口的方法、信号和属性定义。 - 失败:若未找到匹配接口,返回
NULL
。 - 注意:返回的指针为内部引用,无需手动释放,其生命周期与输入的
info
对象绑定。
典型用法示例
-
解析 XML 并查找接口
GDBusNodeInfo *info = g_dbus_node_info_new_for_xml(introspection_xml, NULL); if (info != NULL) {GDBusInterfaceInfo *iface_info = g_dbus_node_info_lookup_interface(info, "org.example.Test");if (iface_info != NULL) {g_print("找到接口: %s\n", iface_info->name);}g_dbus_node_info_unref(info); // 释放节点信息 }
-
验证接口方法是否存在
结合g_dbus_interface_info_lookup_method
可进一步检查接口中的方法:GDBusMethodInfo *method_info = g_dbus_interface_info_lookup_method(iface_info, "ExampleMethod" );
应用场景
- 动态接口注册
在 D-Bus 服务启动时,通过此函数快速定位需注册的接口,避免硬编码。 - 客户端代理验证
客户端在调用远程方法前,可先验证接口是否存在,提高健壮性。 - 自动化代码生成
工具链解析 XML 后,利用此函数遍历接口生成代码桩。
注意事项
- 线程安全:需在主线程调用,非多线程安全。
- 性能:查找时间为 O(n),若频繁调用建议缓存结果。
- 错误处理:始终检查返回值,避免直接解引用
NULL
。
函数g_dbus_connection_register_object的用法
g_dbus_connection_register_object
是 GLib 中用于将本地对象注册到 D-Bus 总线上的核心函数,其作用是将程序内部对象暴露为 D-Bus 服务,供其他进程调用。以下是详细用法说明:
函数原型
guint g_dbus_connection_register_object (GDBusConnection *connection,const gchar *object_path,GDBusInterfaceInfo *interface_info,const GDBusInterfaceVTable *vtable,gpointer user_data,GDestroyNotify user_data_free_func,GError **error
);
参数说明
-
connection
- 类型:
GDBusConnection*
- 作用:已建立的 D-Bus 连接(通过
g_bus_get_sync()
或类似函数获取)。 - 要求:必须为有效连接,否则注册失败。
- 类型:
-
object_path
- 类型:
const gchar*
- 作用:对象路径(如
"/org/example/MyObject"
),需符合 D-Bus 路径规范。 - 注意:路径需唯一,避免与其他服务冲突。
- 类型:
-
interface_info
- 类型:
GDBusInterfaceInfo*
- 作用:接口描述信息,通常通过
g_dbus_node_info_new_for_xml()
解析 XML 生成。 - 示例:包含方法、信号和属性的结构化定义。
- 类型:
-
vtable
- 类型:
GDBusInterfaceVTable*
- 作用:定义接口方法的回调函数表(若为
NULL
,则仅注册接口但不处理调用)。 - 关键回调:
method_call
:处理方法调用请求。get_property
/set_property
:处理属性访问。
- 类型:
-
user_data
- 类型:
gpointer
- 作用:传递给回调函数的用户自定义数据(如对象实例指针)。
- 类型:
-
user_data_free_func
- 类型:
GDestroyNotify
- 作用:释放
user_data
的回调函数(可设为NULL
若无需释放)。
- 类型:
-
error
- 类型:
GError**
- 作用:捕获注册过程中的错误(如路径冲突或权限不足)。
- 类型:
返回值
- 成功时返回注册 ID(
guint
),用于后续通过g_dbus_connection_unregister_object()
注销对象。 - 失败时返回
0
并设置error
参数。
典型用法示例
-
定义接口 XML
<node><interface name="org.example.Test"><method name="Echo"><arg type="s" name="input" direction="in"/><arg type="s" name="output" direction="out"/></method></interface> </node>
-
注册对象到总线
GDBusNodeInfo *info = g_dbus_node_info_new_for_xml(introspection_xml, NULL); GDBusInterfaceVTable vtable = {.method_call = handle_method_call, }; guint id = g_dbus_connection_register_object(connection,"/org/example/Test",info->interfaces[0],&vtable,NULL, // user_dataNULL, // user_data_free_func&error ); if (id == 0) {g_error("注册失败: %s", error->message); }
-
实现方法回调
static void handle_method_call(GDBusConnection *connection,const gchar *sender,const gchar *object_path,const gchar *interface_name,const gchar *method_name,GVariant *parameters,GDBusMethodInvocation *invocation,gpointer user_data ) {if (g_strcmp0(method_name, "Echo") == 0) {const gchar *input;g_variant_get(parameters, "(&s)", &input);g_dbus_method_invocation_return_value(invocation,g_variant_new("(s)", input));} }
使用场景
- 手动注册对象
适用于需要直接控制 D-Bus 消息处理的场景,灵活性高但需自行处理底层细节。 - 与骨架对象对比
相比自动生成的骨架(Skeleton)方式,此函数更适合需要自定义消息分发的场景。
示例代码
#include <gio/gio.h>static void method_call_callback (GDBusConnection *connection,const gchar *sender,const gchar *object_path,const gchar *interface_name,const gchar *method_name,GVariant *parameters,GDBusMethodInvocation *invocation,gpointer user_data) {if (g_strcmp0(method_name, "Hello") == 0) {g_dbus_method_invocation_return_value(invocation, g_variant_new("(s)", "World"));}
}int main() {GError *error = NULL;GDBusConnection *conn = g_bus_get_sync(G_BUS_TYPE_SESSION, NULL, &error);GDBusInterfaceInfo *iface_info = ...; // 从XML加载接口信息GDBusInterfaceVTable vtable = { method_call_callback, NULL, NULL };guint reg_id = g_dbus_connection_register_object(conn,"/com/example/MyObject",iface_info,&vtable,NULL,NULL,&error);if (reg_id == 0) {g_printerr("Registration failed: %s\n", error->message);g_error_free(error);return 1;}// 运行主循环保持服务活跃GMainLoop *loop = g_main_loop_new(NULL, FALSE);g_main_loop_run(loop);return 0;
}
注意事项
-
线程安全
回调函数会在注册时的线程默认主循环中执行,需确保线程上下文安全。 -
生命周期管理
注册的对象会持续有效,直到显式注销或连接关闭1。 -
错误处理
若远程调用参数不符合接口定义,自动返回org.freedesktop.DBus.Error.InvalidArgs
错误。 -
性能优化
频繁调用的服务建议使用骨架(Skeleton)模式,减少动态解析开销。 -
替代方案
对于复杂接口,推荐使用gdbus-codegen
生成骨架代码,简化开发。