找回密码
 立即注册
首页 业界区 安全 D-BUS、GDBUS简述

D-BUS、GDBUS简述

慕疼 昨天 23:40
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)。
1.png

消息总线


  • 消息总线分为:

    • 会话总线(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

    • 被调用方步骤:

      • 建立连接
      • 注册连接名称(必须)
      • 循环监听
      • 解析调用消息并处理

        • 读取消息中携带的参数,进行相应的处理
        • 创建返回消息,将处理结果传入返回消息变量中
        • 发送返回消息


    • 调用方步骤:

      • 建立连接
      • 注册连接名称
      • 创建调用消息(需要被调用方的连接名、对象路径、接口名和方法名),给定调用参数
      • 发送消息
      • 接收响应


信号发送接收示例

发送
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. #include <dbus/dbus.h>
  5. #include <unistd.h>
  6. <p>int send_a_signal(char *sigvalue)
  7. {
  8. // 创建所需变量
  9. DBusError err;
  10. DBusConnection *connection;
  11. DBusMessage *msg;
  12. DBusMessageIter arg;
  13. dbus_uint32_t  serial = 0;
  14. int ret;</p>
  15. [code]// 步骤1:建立与session bus的连接
  16. dbus_error_init(&err);  // 初始化错误结构体
  17. connection = dbus_bus_get(DBUS_BUS_SESSION, &err );  // 获取一个与session bus的连接
  18. if(dbus_error_is_set(&err)){
  19.         fprintf(stderr, "ConnectionErr : %s\n", err.message);
  20.         dbus_error_free(&err);
  21. }
  22. if(connection == NULL)
  23.         return -1;
  24. // 步骤2:给连接注册一个名字,这个步骤不是必须的
复制代码
if 1
  1. ret = dbus_bus_request_name(connection, "org.example.SignalSource", DBUS_NAME_FLAG_REPLACE_EXISTING, &err);
  2. if(dbus_error_is_set(&err)){
  3.         fprintf(stderr,"Name Err :%s\n", err.message);
  4.         dbus_error_free(&err);
  5. }
  6. if(ret != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER)
  7.         return -1;
复制代码
endif
  1. // 步骤3:发送一个信号
  2. // 创建message,message参数中包含这个信号的路径,接口,以及信号名
  3. if((msg = dbus_message_new_signal("/org/example/SignalService/Sender", "org.example.Signal.Test", "Test"))== NULL){
  4.         fprintf(stderr, "MessageNULL\n");
  5.         return -1;
  6. }
  7. // 给这个messge具体的内容
  8. dbus_message_iter_init_append(msg, &arg);
  9. if(!dbus_message_iter_append_basic(&arg, DBUS_TYPE_STRING, &sigvalue)){
  10.         fprintf(stderr, "Out OfMemory!\n");
  11.         return -1;
  12. }
  13. // 步骤4: 将信号通过连接发送
  14. if(!dbus_connection_send(connection, msg, &serial)){
  15.         fprintf(stderr, "Out of Memory!\n");
  16.         return -1;
  17. }
  18. dbus_connection_flush(connection);
  19. printf("Signal Send\n");
  20. // 步骤5: 释放资源。
  21. dbus_message_unref(msg);
  22. return 0;
复制代码
}
int main( int argc, char **argv){
send_a_signal("Hello,world!");
return 0;
}

[/code]
部分函数详述

dbus_connection_send
  1. dbus_bool_t dbus_connection_send(
  2.     DBusConnection *connection,  // D-Bus 连接对象指针
  3.     DBusMessage    *message,     // 待发送的消息对象指针
  4.     dbus_uint32_t  *serial       // 返回消息序列号(可选)
  5. );
复制代码

  • ​connection​

    • 类型:DBusConnection*​
    • 作用:通过 dbus_bus_get(DBUS_BUS_SESSION/SYSTEM, ...) 获取的会话或系统总线连接对象

  • ​message:

    • 类型:DBusMessage*​
    • 作用:需发送的消息对象

  • ​serial:

    • 类型:dbus_uint32_t  ,实质就是无符号32位整数
    • 作用:可选参数。若传入非 NULL 指针,函数会将消息的唯一序列号写入该地址,用于跟踪消息(如调试),该序列号唯一企鹅递增。该消息的值由dbus内部程序写入,使用者不该写入值。

接收
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. #include <dbus/dbus.h>
  5. #include <unistd.h>
  6. <p>void listen_signal()
  7. {
  8. // 创建所需变量
  9. DBusMessage *msg;
  10. DBusMessageIter arg;
  11. DBusConnection *connection;
  12. DBusError err;
  13. int ret;
  14. char * sigvalue;</p>
  15. [code]// 步骤1:建立与session bus的连接
  16. dbus_error_init(&err);
  17. connection = dbus_bus_get(DBUS_BUS_SESSION, &err);
  18. if(dbus_error_is_set(&err)){
  19.         fprintf(stderr, "ConnectionError %s\n", err.message);
  20.         dbus_error_free(&err);
  21. }
  22. if(connection == NULL)
  23. return;
  24. // 步骤2:给连接注册一个名称,非必需但推荐
  25. ret = dbus_bus_request_name(connection, "org.example.SignalReceiver", DBUS_NAME_FLAG_REPLACE_EXISTING, &err);
  26. if(dbus_error_is_set(&err)){
  27.         fprintf(stderr, "Name Error%s\n", err.message);
  28.         dbus_error_free(&err);
  29. }
  30. if(ret != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER)
  31. return;
  32. // 步骤3:添加监听匹配规则
  33. dbus_bus_add_match(connection, "type='signal', interface='org.example.Signal.Test', path='/org/example/SignalService/Sender'", &err);
  34. dbus_connection_flush(connection);  // 立即将规则发送给 dbus-daemon,确保实时生效
  35. if(dbus_error_is_set(&err)){
  36.         fprintf(stderr, "Match Error%s\n", err.message);
  37.         dbus_error_free(&err);
  38. }
  39. // 步骤4:在循环中监听,每隔开1秒,就去试图自己的连接中获取这个信号。这里给出的是从连接中获取任何消息的方式,所以获取后去检查一下这个消息是否我们期望的信号,并获取内容。我们也可以通过这个方式来获取method call消息。
  40. while(1){
  41.         dbus_connection_read_write(connection, 0);  // 非阻塞读写
  42.         msg = dbus_connection_pop_message(connection);
  43.         if(msg == NULL){
  44.                 sleep(1);
  45.                 continue;
  46.         }
  47.         if(dbus_message_is_signal(msg, "org.example.Signal.Test", "Test")){
  48.                 if(!dbus_message_iter_init(msg, &arg))
  49.                         fprintf(stderr, "MessageHas no Param");
  50.                 else if(dbus_message_iter_get_arg_type(&arg) != DBUS_TYPE_STRING)
  51.                         fprintf(stderr, "Param isnot string");
  52.                 else
  53.                         dbus_message_iter_get_basic(&arg, &sigvalue);
  54.                 printf("Got Singal withvalue : %s\n", sigvalue);
  55.         }
  56.         dbus_message_unref(msg);
  57. }//End of while
复制代码
}
int main(int argc, char **argv){
listen_signal();
return 0;
}

[/code]
编译

CMakeLists.txt
  1. cmake_minimum_required(VERSION 3.16)
  2. <p>project(dbus_test)</p>
  3. <p>aux_source_directory(. SRCS)</p>
  4. <p>add_executable(test ${SRCS})</p>
  5. <p>target_link_libraries(test dbus-1)
  6. </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,原因同上

方法调用示例

被调用方
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. #include <dbus/dbus.h>
  5. #include <unistd.h>
  6. <p>void reply_to_method_call(DBusMessage *msg, DBusConnection *conn)
  7. {
  8. DBusMessage *reply;
  9. DBusMessageIter iter;
  10. dbus_uint32_t serial = 0;
  11. int param1, param2;
  12. // 1 读取消息中携带的参数
  13. if(!dbus_message_iter_init(msg, &iter))
  14. {
  15. printf("Message has noargs\n");
  16. return;
  17. }
  18. // 读取第一个参数
  19. if(dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_INT32)
  20. {
  21. printf("arg1 type error, should intger!\n");
  22. return;
  23. }
  24. else
  25. {
  26. dbus_message_iter_get_basic(&iter, &param1);
  27. dbus_message_iter_next(&iter);  // 迭代器后移一位
  28. }
  29. // 读取第二个参数
  30. if(dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_INT32)
  31. {
  32. printf("arg2 type error, should intger!\n");
  33. }
  34. else
  35. {
  36. dbus_message_iter_get_basic(&iter, &param2);
  37. }</p>
  38. [code]printf("receive method call, param is %d and %d\n", param1, param2);
  39. int result = param1 + param2;
  40. // 2 创建返回消息reply
  41. reply = dbus_message_new_method_return(msg);
  42. // 通过消息迭代器在返回消息中填入结果
  43. dbus_message_iter_init_append(reply, &iter);
  44. if(!dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &result)){
  45.         printf("Out ofMemory!\n");
  46.         exit(1);
  47. }
  48. // 3 发送返回消息
  49. if(!dbus_connection_send(conn, reply, &serial)){
  50.         printf("Out of Memory\n");
  51.         exit(1);
  52. }
  53. dbus_connection_flush(conn);
  54. dbus_message_unref(reply);
复制代码
}
void listen_dbus()
{
DBusMessage *msg;
DBusConnection *connection;
DBusError err;
  1. // 步骤1 建立连接
  2. dbus_error_init(&err);
  3. connection = dbus_bus_get(DBUS_BUS_SESSION, &err);
  4. if(dbus_error_is_set(&err)){
  5.     fprintf(stderr, "ConnectionError %s\n", err.message);
  6.     dbus_error_free(&err);
  7. }
  8. if(connection == NULL)
  9.     return;
  10. // 步骤2 设置连接名
  11. int ret = dbus_bus_request_name(connection, "org.example.MethodCallable", DBUS_NAME_FLAG_REPLACE_EXISTING, &err);
  12. if(dbus_error_is_set(&err)){
  13.     fprintf(stderr, "Name Error %s\n", err.message);
  14.     dbus_error_free(&err);
  15. }
  16. while(1)
  17. {
  18.     // 步骤3 循环监听
  19.     dbus_connection_read_write(connection, 0);
  20.         msg = dbus_connection_pop_message(connection);
  21.         if(msg == NULL){
  22.                 sleep(1);
  23.                 continue;
  24.         }
  25.     // 步骤4 解析调用消息并处理
  26.     if(strcmp(dbus_message_get_path(msg), "/org/example/MethodService/Object") == 0){
  27.                 if(dbus_message_is_method_call(msg, "org.example.MethodService.Add", "AddMethod")){
  28.                         reply_to_method_call(msg, connection);
  29.         }
  30.     }
  31.     dbus_message_unref(msg);
  32. }
复制代码
}
int main(int argc, char **argv){
listen_dbus();
return 0;
}

[/code]
调用方
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. #include <dbus/dbus.h>
  5. #include <unistd.h>
  6. <p>DBusConnection* connect_dbus()
  7. {
  8. DBusError err;
  9. DBusConnection *connection;
  10. int ret;</p>
  11. [code]// 步骤1 建立连接
  12. dbus_error_init(&err);       
  13. connection = dbus_bus_get(DBUS_BUS_SESSION, &err);
  14. if(dbus_error_is_set(&err)){
  15.         fprintf(stderr, "ConnectionErr : %s\n", err.message);
  16.         dbus_error_free(&err);
  17. }
  18. if(connection == NULL)
  19.         return NULL;
  20. // 步骤2 注册连接名称
  21. ret = dbus_bus_request_name(connection, "org.example.MethodCall", DBUS_NAME_FLAG_REPLACE_EXISTING, &err);
  22. if(dbus_error_is_set(&err)){
  23.         fprintf(stderr, "Name Err :%s\n", err.message);
  24.         dbus_error_free(&err);
  25. }
  26. if(ret != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER)
  27.         return NULL;
  28. return connection;
复制代码
}
void send_a_method_call(DBusConnection *connection, int param1, int param2)
{
DBusError err;
DBusMessage *msg;
DBusMessageIter iter;
DBusPendingCall *pending;
int result;
  1. // 步骤3 创建调用消息
  2. dbus_error_init(&err);
  3. msg = dbus_message_new_method_call("org.example.MethodCallable", "/org/example/MethodService/Object",
  4.     "org.example.MethodService.Add", "AddMethod");
  5. if(msg == NULL){
  6.         fprintf(stderr, "MessageNULL");
  7.         return;
  8. }
  9. // 给定调用参数
  10. dbus_message_iter_init_append(msg, &iter);
  11. if(!dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &param1)){
  12.         fprintf(stderr, "Out of Memory!");
  13.         exit(1);
  14. }
  15. if(!dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &param2)){
  16.         fprintf(stderr, "Out of Memory!");
  17.         exit(1);
  18. }
  19. // 步骤4 发送消息,pending用于接收调用后的方法响应
  20. if(!dbus_connection_send_with_reply(connection, msg, &pending, -1)){
  21.         fprintf(stderr, "Out of Memory!");
  22.         exit(1);
  23. }
  24. if(pending == NULL){
  25.         fprintf(stderr, "Pending CallNULL: connection is disconnected ");
  26.         dbus_message_unref(msg);
  27.         return;
  28. }
  29. dbus_connection_flush(connection);
  30. dbus_message_unref(msg);
  31. // 步骤5 接收响应
  32. dbus_pending_call_block(pending);
  33. // 从响应中拿取数据
  34. msg = dbus_pending_call_steal_reply(pending);
  35. if (msg == NULL) {
  36.         fprintf(stderr, "ReplyNull\n");
  37.         exit(1);
  38. }
  39. dbus_pending_call_unref(pending);
  40. // 读取响应数据
  41. if(!dbus_message_iter_init(msg, &iter))
  42.         fprintf(stderr, "Message has no ret!\n");
  43. else if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_INT32)
  44.         fprintf(stderr, "Argument is not integer!\n");
  45. else
  46.         dbus_message_iter_get_basic(&iter, &result);
  47. printf("Got Reply: %d\n", result);
  48. dbus_message_unref(msg);
复制代码
}
int main()
{
send_a_method_call(connect_dbus(), 5, 10);
  1. return 0;
复制代码
}

[/code]
GDBUS

reference

Gio – 2.0: 迁移到 GDBus - GTK 文档
常用函数

​g_bus_own_name​

声明
  1. guint
  2. g_bus_own_name (
  3.   GBusType bus_type,
  4.   const gchar* name,
  5.   GBusNameOwnerFlags flags,
  6.   GBusAcquiredCallback bus_acquired_handler,
  7.   GBusNameAcquiredCallback name_acquired_handler,
  8.   GBusNameLostCallback name_lost_handler,
  9.   gpointer user_data,
  10.   GDestroyNotify user_data_free_func
  11. )
复制代码
描述

连接到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​

    • 类型:
      1. void
      2. (* GBusAcquiredCallback) (
      3.   GDBusConnection* connection,
      4.   const gchar* name,
      5.   gpointer user_data
      6. )
      复制代码
    • 说明:在连接到类型为bus_type的总线或NULL时调用的处理程序。

  • ​name_acquired_handler​

    • 类型:
      1. void
      2. (* GBusNameAcquiredCallback) (
      3.   GDBusConnection* connection,
      4.   const gchar* name,
      5.   gpointer user_data
      6. )
      复制代码
    • 说明:在名称被获取时调用。

  • ​name_lost_handler​

    • 类型:
      1. void
      2. (* GBusNameLostCallback) (
      3.   GDBusConnection* connection,
      4.   const gchar* name,
      5.   gpointer user_data
      6. )
      复制代码
    • 说明:当名称丢失或连接被关闭时调用。

  • ​user_data​

    • 类型:gpointer,实质是void*​
    • 说明:传递给处理器的用户数据。参数可以是NULL。数据由函数的调用者拥有。

  • ​user_data_free_func​

    • 类型
      1. void
      2. (* GDestroyNotify) (
      3.   gpointer data
      4. )
      复制代码
    • 说明:指定在销毁数据元素时调用的函数类型。它将指针传递给数据元素,并应释放为此分配的任何内存和资源。参数可以为 NULL。

返回值


  • 类型:guint​
  • 说明:一个可用于与 g_bus_unown_name() 一起使用的标识符(永远不会是 0),用于停止拥有该名称。
g_bus_unown_name​

声明
  1. void
  2. g_bus_unown_name (
  3.   guint owner_id
  4. )
复制代码
描述

停止拥有一个名称。
参数


  • ​owner_id
    ​g_bus_own_name的返回值
​g_signal_connect​

声明
  1. #define g_signal_connect (
  2.   instance,
  3.   detailed_signal,
  4.   c_handler,
  5.   data
  6. )
复制代码
说明:

将 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生成的代码中查找信号名,形如
      1. static const _ExtendedGDBusMethodInfo _example_animal_method_info_poke =
      2. {
      3.   {
      4.     -1,
      5.     (gchar *) "Poke",
      6.     (GDBusArgInfo **) &_example_animal_method_info_poke_IN_ARG_pointers,
      7.     (GDBusArgInfo **) &_example_animal_method_info_poke_OUT_ARG_pointers,
      8.     NULL
      9.   },
      10.   "handle-poke",
      11.   FALSE
      12. };
      复制代码
      形式的结构体赋值语句,结构体的原型为
      1. typedef struct
      2. {
      3.   GDBusMethodInfo parent_struct;
      4.   const gchar *signal_name;
      5.   gboolean pass_fdlist;
      6. } _ExtendedGDBusMethodInfo;
      复制代码
      也就是说,"handle-poke"就是生成代码为Poke方法创建的信号。

  • ​c_handler​

    • 类型:形如
      1. static gboolean on_animal_poke (
      2.     ExampleAnimal *object,
      3.     GDBusMethodInvocation *invocation,
      4.     gboolean arg_make_sad,
      5.     gboolean arg_make_happy,
      6.         gpointer user_data
      7.         )
      复制代码
      形式的函数指针。要使用G_CALLBACK转换该函数指针。
    • 具体说明:相较于生成的头文件中struct _ExampleAnimalIface​
      1. struct _ExampleAnimalIface
      2. {
      3.   GTypeInterface parent_iface;
      4. <p>gboolean (*handle_poke) (
      5. ExampleAnimal *object,
      6. GDBusMethodInvocation *invocation,
      7. gboolean arg_make_sad,
      8. gboolean arg_make_happy);</p>
      9. <p>const gchar * (*get_foo) (ExampleAnimal *object);</p>
      10. <p>const gchar * (*get_mood) (ExampleAnimal *object);</p>
      11. <p>void (*jumped) (
      12. ExampleAnimal *object,
      13. gdouble arg_height);</p>
      14. <p>const gchar * (*get_bar) (ExampleAnimal *object);</p>
      15. <p>};
      16. </p>
      复制代码
      内定义的handle_poke函数指针,该函数中多了一个gpointer类型的参数,gpointer实质是void*类型,用于传递自定义的一些数据。此处的函数指针名称不作要求,但一般形式都是on_接口名_方法名。

  • data

    • 类型:gpointer​
    • 用于传递自定义的一些数据,如不需要,可为NULL

g_main_loop_new​

声明
  1. GMainLoop*
  2. g_main_loop_new (
  3.   GMainContext* context,
  4.   gboolean is_running
  5. )
复制代码
描述

创建一个新的 GMainLoop 结构体。GMainLoop 结构是一个不透明的数据类型,它表示 GLib 或 GTK 应用程序的主事件循环。
参数


  • ​context​

    • 类型:GMainContext*。GMainContext 结构体是不透明的数据类型,用于表示要主循环中处理的一组源。
    • 说明:此参数可以为NULL,如果为 NULL,将使用全局默认的主上下文。数据由函数的调用者持有。

  • ​is_running​

    • 设置为 TRUE 以指示循环正在运行。这并不很重要,因为调用 g\_main\_loop\_run() 无论如何都会将其设置为 TRUE。

返回值


  • 类型:GMainLoop​
  • 说明:一个新的 GMainLoop。函数的调用者负责数据的所有权,并负责释放它。
g_main_loop_run​

声明
  1. void
  2. g_main_loop_run (
  3.   GMainLoop* loop
  4. )
复制代码
描述

运行主循环,直到在循环上调用 g\_main\_loop\_quit()。如果这是在循环的 GMainContext 线程上调用,它将处理循环的事件,否则它将只等待。
参数


  • ​loop​
    ​g_main_loop_new返回的对象
g_main_loop_unref​

声明
  1. void
  2. g_main_loop_unref (
  3.   GMainLoop* loop
  4. )
复制代码
描述

通过一个 GMainLoop 对象的引用次数减一。如果结果是零,则释放循环及其所有相关内存。
g_main_loop_quit​

声明
  1. void
  2. g_main_loop_quit (
  3.   GMainLoop* loop
  4. )
复制代码
描述

停止 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]
您需要登录后才可以回帖 登录 | 立即注册