官方文档:https://developer.gnome.org/gio/
DBus的通信机制是Server-Client模式,Server需要提供一个XML(eg: cn.RTplay.Gdbus.Example.xml)文档给Client端去说明DBus Server提供的interface name、signal name及它的arg name、 type、 direction、method name及它的arg name、 type、 direction。
本例程代码:https://gitee.com/RTplay/gdbus-demo
建议先下载大概看一下。
工程目录结构:
.
├── client
│ ├── CMakeLists.txt
│ └── libClient.c
├── CMakeLists.txt
├── example
│ ├── CltExample.c
│ └── CMakeLists.txt
├── gdbus
│ ├── CMakeLists.txt
│ └── cn.RTplay.Gdbus.Example.xml
├── includes
│ ├── dbusCommon.h
│ └── libClient.h
├── README.en.md
├── README.md
└── server
├── CMakeLists.txt
├── libServer.c
├── libServer.h
└── SvrExample.c
程序架构大致会按照这样一个思路:
Server、Client端会首先依赖XML产生的ExampleGdbusGenerated.h and ExampleGdbusGenerated.c两个文件,客户端封装相应的接口而产生一个动态库,然后需要与服务端通信的只需要引用库,并且调用库里的接口即可。然后编写两个应用测试程序去测试服务端和客户端的DBus同步、异步接口。
在xml中需要定义参数类型,可惜的是xml中的参数类型并不是c语言中的写法,在附录中有字符和类型的对应关系。
生成的ExampleGdbusGenerated.h and ExampleGdbusGenerated.c两个文件中的函数说明。
//客户端中使用的同步接口。
gboolean rtplay_gdbus_example_call_my_method1_sync (
RTplayGdbusExample *proxy,
const gchar *arg_InArg,
gchar **out_OutArg,
GCancellable *cancellable,
GError **error);
gboolean rtplay_gdbus_example_call_my_method2_sync (
RTplayGdbusExample *proxy,
GVariant *arg_InArg,
GVariant **out_OutArg,
GCancellable *cancellable,
GError **error);
//客户端中使用的异步接口。
//方法调用
void rtplay_gdbus_example_call_my_method1 (
RTplayGdbusExample *proxy,
const gchar *arg_InArg,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data);
//回调中返回值获取
gboolean rtplay_gdbus_example_call_my_method1_finish (
RTplayGdbusExample *proxy,
gchar **out_OutArg,
GAsyncResult *res,
GError **error);
void rtplay_gdbus_example_call_my_method2 (
RTplayGdbusExample *proxy,
GVariant *arg_InArg,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data);
gboolean rtplay_gdbus_example_call_my_method2_finish (
RTplayGdbusExample *proxy,
GVariant **out_OutArg,
GAsyncResult *res,
GError **error);
//服务端发送信号接口。
void rtplay_gdbus_example_emit_my_signal1 (
RTplayGdbusExample *object,
const gchar *arg_Value);
void rtplay_gdbus_example_emit_my_signal2 (
RTplayGdbusExample *object,
GVariant *arg_Value);
//当服务端的方法被调用时,使用下面接口返回给返回值。
void rtplay_gdbus_example_complete_my_method1 (
RTplayGdbusExample *object,
GDBusMethodInvocation *invocation,
const gchar *OutArg);
void rtplay_gdbus_example_complete_my_method2 (
RTplayGdbusExample *object,
GDBusMethodInvocation *invocation,
GVariant *OutArg);
服务端流程如下:
1、创建main loop,但不开启
pLoop = g_main_loop_new(NULL, FALSE);
2、链接总线,获取自己在总线上的名字
(void)g_bus_own_name(RTPLAY_GDBUS_EXAMPLE_BUS,
RTPLAY_GDBUS_EXAMPLE_BUS_NAME,
G_BUS_NAME_OWNER_FLAGS_NONE,
&bus_acquired_cb,
&name_acquired_cb,
&name_lost_cb,
NULL,
NULL);
在GBusAcquiredCallback回调函数中
3、初始化骨架
pSkeleton = rtplay_gdbus_example_skeleton_new();
4、链接信号
(void) g_signal_connect(pSkeleton, "handle-my-method1", G_CALLBACK(My_Method1), NULL);
(void) g_signal_connect(pSkeleton, "handle-my-method2", G_CALLBACK(My_Method2), NULL);
5、绑定骨架接口
(void) g_dbus_interface_skeleton_export(G_DBUS_INTERFACE_SKELETON(pSkeleton),
connection,
RTPLAY_GDBUS_EXAMPLE_OBJECT_PATH,
&pError);
6、开启main loop
g_main_loop_run( pLoop );
客户端流程如下:
1、创建main loop,但不开启
pLoop = g_main_loop_new(NULL, FALSE);
2、同步创建一个Connection
pConnection = g_bus_get_sync(RTPLAY_GDBUS_EXAMPLE_BUS, NULL, &pConnError);
3、同步创建一个proxy
pProxy = rtplay_gdbus_example_proxy_new_sync(pConnection,
G_DBUS_PROXY_FLAGS_NONE,
RTPLAY_GDBUS_EXAMPLE_BUS_NAME,
RTPLAY_GDBUS_EXAMPLE_OBJECT_PATH,
NULL,
&pProxyError);
4、将信号与proxy绑定
g_RetSignalHandler[0] = g_signal_connect(pProxy, "notify::g-name-owner", G_CALLBACK(cb_OwnerNameChangedNotify), NULL);
g_RetSignalHandler[1] = g_signal_connect(pProxy, "my-signal1", G_CALLBACK(My_Signal_1_Handler), NULL);
g_RetSignalHandler[2] = g_signal_connect(pProxy, "my-signal2", G_CALLBACK(My_Signal_2_Handler), NULL);
5、开启main loop
g_main_loop_run( pLoop );
附录:
每个字符的含义如下:
b:G_VARIANT_TYPE_BOOLEAN的类型字符串; 布尔值。
y:G_VARIANT_TYPE_BYTE的类型字符串; 一个字节。
n:G_VARIANT_TYPE_INT16的类型字符串; 有符号的16位整数。
q:G_VARIANT_TYPE_UINT16的类型字符串; 一个无符号的16位整数。
i:G_VARIANT_TYPE_INT32的类型字符串; 有符号的32位整数。
u:G_VARIANT_TYPE_UINT32的类型字符串; 一个无符号的32位整数。
x:G_VARIANT_TYPE_INT64的类型字符串; 有符号的64位整数。
t:G_VARIANT_TYPE_UINT64的类型字符串; 一个无符号的64位整数。
h:G_VARIANT_TYPE_HANDLE的类型字符串; 一个有符号的32位值,按照惯例,该值用作与D-Bus消息一起发送的文件描述符数组的索引。
d:G_VARIANT_TYPE_DOUBLE的类型字符串; 双精度浮点值。
s:G_VARIANT_NEW_STRING的类型字符串; 一个字符串。
o:G_VARIANT_TYPE_OBJECT_PATH的类型字符串; D-Bus对象路径形式的字符串。
g:G_VARIANT_TYPE_SIGNATURE的类型字符串; D-Bus类型签名形式的字符串。
?:G_VARIANT_TYPE_BASIC的类型字符串; 一个不确定类型,它是任何基本类型的超类型。
v:G_VARIANT_TYPE_VARIANT的类型字符串; 包含任何其他类型的值的容器类型。
a:用作另一个类型字符串的前缀,表示该类型的数组; 例如,类型字符串“ ai”是带符号的32位整数数组的类型。
m:用作另一个类型字符串的前缀,表示该类型的“也许”或“可空”版本; 例如,类型字符串“ ms”是可能包含字符串或不包含任何值的值的类型。
():用于封装零个或多个其他串联类型的字符串以创建元组类型; 例如,类型字符串“(is)”,是整数和字符串对的类型。
r:G_VARIANT_TYPE_TUPLE的类型字符串; 一个不定类型,它是任何元组类型的超类型,而与元素数无关。
{}:用于将基本类型字符串与另一个类型字符串连接起来以创建字典条目类型,该字典条目类型通常出现在数组内部以形成字典; 例如,类型字符串“ a {sd}”是将字符串映射到双精度浮点值的字典的类型。
第一种类型(基本类型)是键类型,第二种类型是值类型。 第一种类型被限制为基本类型的原因是为了可以轻松地对其进行哈希处理。
*:G_VARIANT_TYPE_ANY的类型字符串; 不定类型,它是所有类型的超类型。 请注意,与所有类型字符串一样,此字符恰好表示一种类型。 在元组内部不能使用它来表示“任何数量的项目”。
参考:
基于GDBus技术的IPC通信编程详解(1)
https://blog.csdn.net/adlindary/article/details/80167840
gdbus demo程序简介
https://blog.csdn.net/quinta2008/article/details/78472170
GDBus 通信机制介绍及Demo版本
https://blog.csdn.net/yanlinembed/article/details/46985605