D-BUS、GDBUS简述
D-BUS、GDBUS简述
D-BUS简述
reference :
https://blog.csdn.net/f110300641/article/details/106823611,
https://dbus.freedesktop.org/doc/dbus-specification.html,
Linux进程间通信:dbus的使用(2)—— D-Bus介绍及signal、method测试例程_dbus signal-CSDN博客
D-BUS是一种低开销、易于使用的进程间通信系统(IPC)。
消息总线
- 消息总线分为:
- 会话总线(session bus)
- 系统总线(system bus)
特性Session BusSystem Bus启动时机用户登录时系统启动时(由 systemd 管理)权限用户级权限root 权限配置文件session.conf,用户级服务描述文件system.conf,系统服务描述文件典型应用桌面应用集成(如通知系统)硬件事件(如 USB 插入)、系统服务通信地址固定性动态地址(环境变量指定)固定地址(/var/run/dbus/system_bus_socket)
- dbus-daemon(消息总线守护进程 )
- dbus-daemon与session bus是一一对应的,每个活跃的用户会话(Session)都拥有一个独立的 dbus-daemon 进程,专门负责管理该会话内的所有消息路由和服务注册。二者是同一实体的逻辑与物理表现。
- 此进程的生命周期与用户会话绑定:用户登录时创建,用户注销时终止。
- system bus同样有一个对应的dbus-daemon。
消息
- dbus中的消息有四种类型:
- method call
- method return
- signal
- error
- signal与method的区别:
- signal是一对多,method是一对一
- signal是单向的,不返回。method消息发出后,发出方会收到返回消息。
对象路径、接口
- 连接(Bus name)标识与会话总线的连接,表示一个dbus服务
- 对象路径(Object Path)唯一标识服务中的对象实例(类似文件路径),标识资源的路径。命名规则:采用斜杠分隔的层次结构,如 /org/kde/Device1。
- 接口名称(Interface Name),定义对象的能力契约,包含方法、信号和属性(类似抽象类)。可以被不同的对象实现。采用反向域名格式(如 org.freedesktop.DBus.Properties),需在总线范围内唯一。接口与对象是解耦的,二者名称并不需要严格对应。
- 方法和信号隶属于接口。
层级关系:
Bus name -》Path-》Interface-》Method/Signal
D-BUS使用
- 安装:sudo apt install dbus
- 包含头文件:#include
- signal
- 发送方步骤:
- 建立与会话总线的连接
- 给该连接注册名称(可选)
- 创建信号
- 发送信号
- 释放资源
- 接收方步骤:
- 建立与会话总线的连接
- 给该连接注册名称(可选)
- 添加监听匹配规则(需要发送方的接口名、信号名,以及路径(可选),如果给定路径,则只接收该路径对象的信号,否则接收所有实现该接口的对象信号)
- 循环监听
- 信号参数解析
- method_call & method_reply
- 被调用方步骤:
- 建立连接
- 注册连接名称(必须)
- 循环监听
- 解析调用消息并处理
- 读取消息中携带的参数,进行相应的处理
- 创建返回消息,将处理结果传入返回消息变量中
- 发送返回消息
- 调用方步骤:
- 建立连接
- 注册连接名称
- 创建调用消息(需要被调用方的连接名、对象路径、接口名和方法名),给定调用参数
- 发送消息
- 接收响应
信号发送接收示例
发送
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <dbus/dbus.h>
- #include <unistd.h>
- <p>int send_a_signal(char *sigvalue)
- {
- // 创建所需变量
- DBusError err;
- DBusConnection *connection;
- DBusMessage *msg;
- DBusMessageIter arg;
- dbus_uint32_t serial = 0;
- int ret;</p>
- [code]// 步骤1:建立与session bus的连接
- dbus_error_init(&err); // 初始化错误结构体
- connection = dbus_bus_get(DBUS_BUS_SESSION, &err ); // 获取一个与session bus的连接
- if(dbus_error_is_set(&err)){
- fprintf(stderr, "ConnectionErr : %s\n", err.message);
- dbus_error_free(&err);
- }
- if(connection == NULL)
- return -1;
- // 步骤2:给连接注册一个名字,这个步骤不是必须的
复制代码 if 1
- ret = dbus_bus_request_name(connection, "org.example.SignalSource", DBUS_NAME_FLAG_REPLACE_EXISTING, &err);
- if(dbus_error_is_set(&err)){
- fprintf(stderr,"Name Err :%s\n", err.message);
- dbus_error_free(&err);
- }
- if(ret != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER)
- return -1;
复制代码 endif
- // 步骤3:发送一个信号
- // 创建message,message参数中包含这个信号的路径,接口,以及信号名
- if((msg = dbus_message_new_signal("/org/example/SignalService/Sender", "org.example.Signal.Test", "Test"))== NULL){
- fprintf(stderr, "MessageNULL\n");
- return -1;
- }
- // 给这个messge具体的内容
- dbus_message_iter_init_append(msg, &arg);
- if(!dbus_message_iter_append_basic(&arg, DBUS_TYPE_STRING, &sigvalue)){
- fprintf(stderr, "Out OfMemory!\n");
- return -1;
- }
- // 步骤4: 将信号通过连接发送
- if(!dbus_connection_send(connection, msg, &serial)){
- fprintf(stderr, "Out of Memory!\n");
- return -1;
- }
- dbus_connection_flush(connection);
- printf("Signal Send\n");
- // 步骤5: 释放资源。
- dbus_message_unref(msg);
- return 0;
复制代码 }
int main( int argc, char **argv){
send_a_signal("Hello,world!");
return 0;
}
[/code]
部分函数详述
dbus_connection_send- dbus_bool_t dbus_connection_send(
- DBusConnection *connection, // D-Bus 连接对象指针
- DBusMessage *message, // 待发送的消息对象指针
- dbus_uint32_t *serial // 返回消息序列号(可选)
- );
复制代码
- connection:
- 类型:DBusConnection*
- 作用:通过 dbus_bus_get(DBUS_BUS_SESSION/SYSTEM, ...) 获取的会话或系统总线连接对象
- message:
- 类型:DBusMessage*
- 作用:需发送的消息对象
- serial:
- 类型:dbus_uint32_t ,实质就是无符号32位整数
- 作用:可选参数。若传入非 NULL 指针,函数会将消息的唯一序列号写入该地址,用于跟踪消息(如调试),该序列号唯一企鹅递增。该消息的值由dbus内部程序写入,使用者不该写入值。
接收
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <dbus/dbus.h>
- #include <unistd.h>
- <p>void listen_signal()
- {
- // 创建所需变量
- DBusMessage *msg;
- DBusMessageIter arg;
- DBusConnection *connection;
- DBusError err;
- int ret;
- char * sigvalue;</p>
- [code]// 步骤1:建立与session bus的连接
- dbus_error_init(&err);
- connection = dbus_bus_get(DBUS_BUS_SESSION, &err);
- if(dbus_error_is_set(&err)){
- fprintf(stderr, "ConnectionError %s\n", err.message);
- dbus_error_free(&err);
- }
- if(connection == NULL)
- return;
- // 步骤2:给连接注册一个名称,非必需但推荐
- ret = dbus_bus_request_name(connection, "org.example.SignalReceiver", DBUS_NAME_FLAG_REPLACE_EXISTING, &err);
- if(dbus_error_is_set(&err)){
- fprintf(stderr, "Name Error%s\n", err.message);
- dbus_error_free(&err);
- }
- if(ret != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER)
- return;
- // 步骤3:添加监听匹配规则
- dbus_bus_add_match(connection, "type='signal', interface='org.example.Signal.Test', path='/org/example/SignalService/Sender'", &err);
- dbus_connection_flush(connection); // 立即将规则发送给 dbus-daemon,确保实时生效
- if(dbus_error_is_set(&err)){
- fprintf(stderr, "Match Error%s\n", err.message);
- dbus_error_free(&err);
- }
- // 步骤4:在循环中监听,每隔开1秒,就去试图自己的连接中获取这个信号。这里给出的是从连接中获取任何消息的方式,所以获取后去检查一下这个消息是否我们期望的信号,并获取内容。我们也可以通过这个方式来获取method call消息。
- while(1){
- dbus_connection_read_write(connection, 0); // 非阻塞读写
- msg = dbus_connection_pop_message(connection);
- if(msg == NULL){
- sleep(1);
- continue;
- }
- if(dbus_message_is_signal(msg, "org.example.Signal.Test", "Test")){
- if(!dbus_message_iter_init(msg, &arg))
- fprintf(stderr, "MessageHas no Param");
- else if(dbus_message_iter_get_arg_type(&arg) != DBUS_TYPE_STRING)
- fprintf(stderr, "Param isnot string");
- else
- dbus_message_iter_get_basic(&arg, &sigvalue);
- printf("Got Singal withvalue : %s\n", sigvalue);
- }
- dbus_message_unref(msg);
- }//End of while
复制代码 }
int main(int argc, char **argv){
listen_signal();
return 0;
}
[/code]
编译
CMakeLists.txt
- cmake_minimum_required(VERSION 3.16)
- <p>project(dbus_test)</p>
- <p>aux_source_directory(. SRCS)</p>
- <p>add_executable(test ${SRCS})</p>
- <p>target_link_libraries(test dbus-1)
- </p>
复制代码 编译可能遇到的问题
- 缺少,解决方法:
- 安装dbus库,若仍未解决,执行下一步
- sudo ln -sf /usr/include/dbus-1.0/dbus /usr/include/dbus,原因:
- 默认安装的dbus可能在/usr/include/dbus-1.0下
- 而程序中自动包含的头文件默认是去/usr/include下查找,上述操作是在/usr/include创建了所需头文件的软连接
- 缺少dbus-arch-deps.h,解决方法:
- sudo ln -sf /usr/include/dbus-1.0/dbus/dbus-arch-deps.h /usr/include/dbus,原因同上
方法调用示例
被调用方
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <dbus/dbus.h>
- #include <unistd.h>
- <p>void reply_to_method_call(DBusMessage *msg, DBusConnection *conn)
- {
- DBusMessage *reply;
- DBusMessageIter iter;
- dbus_uint32_t serial = 0;
- int param1, param2;
- // 1 读取消息中携带的参数
- if(!dbus_message_iter_init(msg, &iter))
- {
- printf("Message has noargs\n");
- return;
- }
- // 读取第一个参数
- if(dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_INT32)
- {
- printf("arg1 type error, should intger!\n");
- return;
- }
- else
- {
- dbus_message_iter_get_basic(&iter, ¶m1);
- dbus_message_iter_next(&iter); // 迭代器后移一位
- }
- // 读取第二个参数
- if(dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_INT32)
- {
- printf("arg2 type error, should intger!\n");
- }
- else
- {
- dbus_message_iter_get_basic(&iter, ¶m2);
- }</p>
- [code]printf("receive method call, param is %d and %d\n", param1, param2);
- int result = param1 + param2;
- // 2 创建返回消息reply
- reply = dbus_message_new_method_return(msg);
- // 通过消息迭代器在返回消息中填入结果
- dbus_message_iter_init_append(reply, &iter);
- if(!dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &result)){
- printf("Out ofMemory!\n");
- exit(1);
- }
- // 3 发送返回消息
- if(!dbus_connection_send(conn, reply, &serial)){
- printf("Out of Memory\n");
- exit(1);
- }
- dbus_connection_flush(conn);
- dbus_message_unref(reply);
复制代码 }
void listen_dbus()
{
DBusMessage *msg;
DBusConnection *connection;
DBusError err;- // 步骤1 建立连接
- dbus_error_init(&err);
- connection = dbus_bus_get(DBUS_BUS_SESSION, &err);
- if(dbus_error_is_set(&err)){
- fprintf(stderr, "ConnectionError %s\n", err.message);
- dbus_error_free(&err);
- }
- if(connection == NULL)
- return;
- // 步骤2 设置连接名
- int ret = dbus_bus_request_name(connection, "org.example.MethodCallable", DBUS_NAME_FLAG_REPLACE_EXISTING, &err);
- if(dbus_error_is_set(&err)){
- fprintf(stderr, "Name Error %s\n", err.message);
- dbus_error_free(&err);
- }
- while(1)
- {
- // 步骤3 循环监听
- dbus_connection_read_write(connection, 0);
- msg = dbus_connection_pop_message(connection);
- if(msg == NULL){
- sleep(1);
- continue;
- }
- // 步骤4 解析调用消息并处理
- if(strcmp(dbus_message_get_path(msg), "/org/example/MethodService/Object") == 0){
- if(dbus_message_is_method_call(msg, "org.example.MethodService.Add", "AddMethod")){
- reply_to_method_call(msg, connection);
- }
- }
- dbus_message_unref(msg);
- }
复制代码 }
int main(int argc, char **argv){
listen_dbus();
return 0;
}
[/code]
调用方
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <dbus/dbus.h>
- #include <unistd.h>
- <p>DBusConnection* connect_dbus()
- {
- DBusError err;
- DBusConnection *connection;
- int ret;</p>
- [code]// 步骤1 建立连接
- dbus_error_init(&err);
- connection = dbus_bus_get(DBUS_BUS_SESSION, &err);
- if(dbus_error_is_set(&err)){
- fprintf(stderr, "ConnectionErr : %s\n", err.message);
- dbus_error_free(&err);
- }
- if(connection == NULL)
- return NULL;
- // 步骤2 注册连接名称
- ret = dbus_bus_request_name(connection, "org.example.MethodCall", DBUS_NAME_FLAG_REPLACE_EXISTING, &err);
- if(dbus_error_is_set(&err)){
- fprintf(stderr, "Name Err :%s\n", err.message);
- dbus_error_free(&err);
- }
- if(ret != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER)
- return NULL;
- return connection;
复制代码 }
void send_a_method_call(DBusConnection *connection, int param1, int param2)
{
DBusError err;
DBusMessage *msg;
DBusMessageIter iter;
DBusPendingCall *pending;
int result;- // 步骤3 创建调用消息
- dbus_error_init(&err);
- msg = dbus_message_new_method_call("org.example.MethodCallable", "/org/example/MethodService/Object",
- "org.example.MethodService.Add", "AddMethod");
- if(msg == NULL){
- fprintf(stderr, "MessageNULL");
- return;
- }
- // 给定调用参数
- dbus_message_iter_init_append(msg, &iter);
- if(!dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, ¶m1)){
- fprintf(stderr, "Out of Memory!");
- exit(1);
- }
- if(!dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, ¶m2)){
- fprintf(stderr, "Out of Memory!");
- exit(1);
- }
- // 步骤4 发送消息,pending用于接收调用后的方法响应
- if(!dbus_connection_send_with_reply(connection, msg, &pending, -1)){
- fprintf(stderr, "Out of Memory!");
- exit(1);
- }
- if(pending == NULL){
- fprintf(stderr, "Pending CallNULL: connection is disconnected ");
- dbus_message_unref(msg);
- return;
- }
- dbus_connection_flush(connection);
- dbus_message_unref(msg);
- // 步骤5 接收响应
- dbus_pending_call_block(pending);
- // 从响应中拿取数据
- msg = dbus_pending_call_steal_reply(pending);
- if (msg == NULL) {
- fprintf(stderr, "ReplyNull\n");
- exit(1);
- }
- dbus_pending_call_unref(pending);
- // 读取响应数据
- if(!dbus_message_iter_init(msg, &iter))
- fprintf(stderr, "Message has no ret!\n");
- else if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_INT32)
- fprintf(stderr, "Argument is not integer!\n");
- else
- dbus_message_iter_get_basic(&iter, &result);
- printf("Got Reply: %d\n", result);
- dbus_message_unref(msg);
复制代码 }
int main()
{
send_a_method_call(connect_dbus(), 5, 10);}
[/code]
GDBUS
reference
Gio – 2.0: 迁移到 GDBus - GTK 文档
常用函数
g_bus_own_name
声明
- guint
- g_bus_own_name (
- GBusType bus_type,
- const gchar* name,
- GBusNameOwnerFlags flags,
- GBusAcquiredCallback bus_acquired_handler,
- GBusNameAcquiredCallback name_acquired_handler,
- GBusNameLostCallback name_lost_handler,
- gpointer user_data,
- GDestroyNotify user_data_free_func
- )
复制代码 描述
连接到bus_type指定的总线,并在该总线注册一个连接名称,在总线获取成功时调用bus_acquired_handler,并分别在名称获取或丢失时调用name_acquired_handler和name_lost_handler。
参数
- **bus\_type**
- 类型:GBusType
- 说明:一般都是G_BUS_TYPE_SESSION
- name
- 类型:const gchar*
- 要给本连接注册的well-known名称
- flags
- 类型:GBusNameOwnerFlags
- 说明:多数时取值G_BUS_NAME_OWNER_FLAGS_REPLACE| G_BUS_NAME_OWNER_FLAGS_ALLOW_REPLACEMENT,意为如果另一个消息总线连接拥有该名称并指定了 G_BUS_NAME_OWNER_FLAGS_ALLOW_REPLACEMENT,则从该连接中取走该名称。
- bus_acquired_handler
- 类型:
- void
- (* GBusAcquiredCallback) (
- GDBusConnection* connection,
- const gchar* name,
- gpointer user_data
- )
复制代码 - 说明:在连接到类型为bus_type的总线或NULL时调用的处理程序。
- name_acquired_handler
- 类型:
- void
- (* GBusNameAcquiredCallback) (
- GDBusConnection* connection,
- const gchar* name,
- gpointer user_data
- )
复制代码 - 说明:在名称被获取时调用。
- name_lost_handler
- 类型:
- void
- (* GBusNameLostCallback) (
- GDBusConnection* connection,
- const gchar* name,
- gpointer user_data
- )
复制代码 - 说明:当名称丢失或连接被关闭时调用。
- user_data
- 类型:gpointer,实质是void*
- 说明:传递给处理器的用户数据。参数可以是NULL。数据由函数的调用者拥有。
- user_data_free_func
- 类型
- void
- (* GDestroyNotify) (
- gpointer data
- )
复制代码 - 说明:指定在销毁数据元素时调用的函数类型。它将指针传递给数据元素,并应释放为此分配的任何内存和资源。参数可以为 NULL。
返回值
- 类型:guint
- 说明:一个可用于与 g_bus_unown_name() 一起使用的标识符(永远不会是 0),用于停止拥有该名称。
g_bus_unown_name
声明
- void
- g_bus_unown_name (
- guint owner_id
- )
复制代码 描述
停止拥有一个名称。
参数
- owner_id
g_bus_own_name的返回值
g_signal_connect
声明
- #define g_signal_connect (
- instance,
- detailed_signal,
- c_handler,
- data
- )
复制代码 说明:
将 GCallback 函数连接到特定对象的信号。这里是这样一种思想:XML文件中定义了Method,客户端调用该Method时,会向服务端发出一个处理该方法的信号。若是服务端使用此函数将信号与一个回调函数连接,就会在收到信号时触发该回调函数。这种handle-method信号由gdbus-codegen工具根据XML文件中定义的方法自动生成的信号。
详细说明:GObject.signal_connect - GTK 文档。
参数
- instance
- 类型:形如ExampleAnimal,是由gdbus-codegen工具根据XML文件生成的文件中定义的结构体类型。
- 具体内容:形如example_animal_skeleton_new()函数创建的对象实例。标识
example_animal_skeleton_new也是gdbus-codegen工具根据XML文件生成的函数。
example_animal是根据gdbus-codegen工具选项和XML文件内容生成的名称,会作为所有生成的函数或是宏的名称的前缀。其中example是gdbus-codegen工具选项--c-namespace Example定义的,animal则是XML文件中定义的接口名称。
- detailed_signal
- 类型:一个标识XML文件中定义的方法的字符串。
- 具体内容:handle-{methodname},其中handle是固定前缀,methodname是由XML文件中定义的方法名转换而来的。具体转换方式为从驼峰命名转换成小写且以-连接。如GetIp → get-ip。可以在gdbus-codegen生成的代码中查找信号名,形如
- static const _ExtendedGDBusMethodInfo _example_animal_method_info_poke =
- {
- {
- -1,
- (gchar *) "Poke",
- (GDBusArgInfo **) &_example_animal_method_info_poke_IN_ARG_pointers,
- (GDBusArgInfo **) &_example_animal_method_info_poke_OUT_ARG_pointers,
- NULL
- },
- "handle-poke",
- FALSE
- };
复制代码 形式的结构体赋值语句,结构体的原型为- typedef struct
- {
- GDBusMethodInfo parent_struct;
- const gchar *signal_name;
- gboolean pass_fdlist;
- } _ExtendedGDBusMethodInfo;
复制代码 也就是说,"handle-poke"就是生成代码为Poke方法创建的信号。
- c_handler
- 类型:形如
- static gboolean on_animal_poke (
- ExampleAnimal *object,
- GDBusMethodInvocation *invocation,
- gboolean arg_make_sad,
- gboolean arg_make_happy,
- gpointer user_data
- )
复制代码 形式的函数指针。要使用G_CALLBACK转换该函数指针。
- 具体说明:相较于生成的头文件中struct _ExampleAnimalIface
- struct _ExampleAnimalIface
- {
- GTypeInterface parent_iface;
- <p>gboolean (*handle_poke) (
- ExampleAnimal *object,
- GDBusMethodInvocation *invocation,
- gboolean arg_make_sad,
- gboolean arg_make_happy);</p>
- <p>const gchar * (*get_foo) (ExampleAnimal *object);</p>
- <p>const gchar * (*get_mood) (ExampleAnimal *object);</p>
- <p>void (*jumped) (
- ExampleAnimal *object,
- gdouble arg_height);</p>
- <p>const gchar * (*get_bar) (ExampleAnimal *object);</p>
- <p>};
- </p>
复制代码 内定义的handle_poke函数指针,该函数中多了一个gpointer类型的参数,gpointer实质是void*类型,用于传递自定义的一些数据。此处的函数指针名称不作要求,但一般形式都是on_接口名_方法名。
- data
- 类型:gpointer
- 用于传递自定义的一些数据,如不需要,可为NULL
g_main_loop_new
声明
- GMainLoop*
- g_main_loop_new (
- GMainContext* context,
- gboolean is_running
- )
复制代码 描述
创建一个新的 GMainLoop 结构体。GMainLoop 结构是一个不透明的数据类型,它表示 GLib 或 GTK 应用程序的主事件循环。
参数
- context
- 类型:GMainContext*。GMainContext 结构体是不透明的数据类型,用于表示要主循环中处理的一组源。
- 说明:此参数可以为NULL,如果为 NULL,将使用全局默认的主上下文。数据由函数的调用者持有。
- is_running
- 设置为 TRUE 以指示循环正在运行。这并不很重要,因为调用 g\_main\_loop\_run() 无论如何都会将其设置为 TRUE。
返回值
- 类型:GMainLoop
- 说明:一个新的 GMainLoop。函数的调用者负责数据的所有权,并负责释放它。
g_main_loop_run
声明
- void
- g_main_loop_run (
- GMainLoop* loop
- )
复制代码 描述
运行主循环,直到在循环上调用 g\_main\_loop\_quit()。如果这是在循环的 GMainContext 线程上调用,它将处理循环的事件,否则它将只等待。
参数
- loop
g_main_loop_new返回的对象
g_main_loop_unref
声明
- void
- g_main_loop_unref (
- GMainLoop* loop
- )
复制代码 描述
通过一个 GMainLoop 对象的引用次数减一。如果结果是零,则释放循环及其所有相关内存。
g_main_loop_quit
声明
- void
- g_main_loop_quit (
- GMainLoop* loop
- )
复制代码 描述
停止 GMainLoop 的运行。对于此循环的任何 g\_main\_loop\_run() 调用都将返回。
注意,当调用 g\_main\_loop\_quit() 时,已调度的事件源仍将被执行。
流程
服务端流程
- g_main_loop_new创建主事件循环对象
- g_bus_own_name创建连接并注册连接名称,且注册回调函数(所有事件都在回调函数中处理)
- g_main_loop_run启动主事件循环
- g_bus_unown_name停止拥有之前注册的连接名称
- g_main_loop_unref释放主事件循环对象资源
客户端流程
- g_main_loop_new创建主事件循环对象
- example_object_manager_client_new_for_bus_sync同步创建并返回一个对象管理代理客户端(该函数是gdbus-codegen根据XML文件生成的头文件和源文件中包含的函数,并且有异步版本)
- 使用上一步获取到的对象管理代理客户端,进行方法调用,以及可选的连接该对象的信号和回调函数。
- g_main_loop_run启动主事件循环
- 停止循环,释放资源
编码流程
- 创建XML文件,在其中写定接口,接口中包含方法、信号、属性等定义;
- 使用gdbus-codegen工具根据XML文件生成代码,包括一个头文件和一个源文件;
- 引入生成的头文件,利用其中包含的函数和宏等编写代码;
- 编译运行。
示例代码
gdbus-example-objectmanager.xml
[code] |