慕疼 发表于 2025-8-3 23:40:35

D-BUS、GDBUS简述

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_tserial = 0;

int ret;</p>
// 步骤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;
}


部分函数详述

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>
// 步骤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;
}


编译

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, &param1);

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, &param2);

}</p>
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;
}


调用方

#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>
// 步骤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, &param1)){
        fprintf(stderr, "Out of Memory!");
        exit(1);
}

if(!dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &param2)){
        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);
return 0;}


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​

页: [1]
查看完整版本: D-BUS、GDBUS简述