【Linux dbus】2-dbus发送消息(以创建方法调用为例)的过程

消息(方法调用)创建后的典型流程

仅仅创建消息头是不够的,完整的调用流程如下:

  1. 创建方法调用消息 - dbus_message_new_method_call

  2. 添加参数 - dbus_message_append_args

  3. 发送消息 - dbus_connection_send

  4. (可选)等待并获取回复 - dbus_connection_send_with_reply_and_block

同系列类似函数的对比

为了更好地理解,这里有几个相关的函数:

 
函数 用途 类比
dbus_message_new_method_call 创建方法调用(客户端) 写一封请求信:"请执行X方法"
dbus_message_new_signal 创建信号消息 发一个广播通知:"某事件发生了"
dbus_message_new_method_return 创建方法回复(服务端) 回信:"方法执行结果是这样"
dbus_message_new_error 创建错误回复(服务端) 回信:"执行出错了"

 

使用示例

让我们通过几个具体例子来理解:

示例1:调用一个无参数的方法

// 让VLC播放器开始播放
DBusMessage *message = dbus_message_new_method_call(
    "org.mpris.MediaPlayer2.vlc",  // 目标服务
    "/org/mpris/MediaPlayer2",     // 对象路径
    "org.mpris.MediaPlayer2.Player", // 接口
    "Play"                         // 方法名
);

if (message == NULL) {
    fprintf(stderr, "创建消息失败:内存不足\n");
    return;
}

// 发送消息(不等待回复)
dbus_connection_send(connection, message, NULL);
dbus_message_unref(message);  // 重要:释放消息

示例2:调用带参数的方法

// 调用计算器服务的加法方法:Add(10, 20)
DBusMessage *message = dbus_message_new_method_call(
    "com.example.Calculator",
    "/com/example/Calculator",
    "com.example.Calculator.Basic",
    "Add"
);

if (message == NULL) {
    fprintf(stderr, "创建消息失败\n");
    return;
}

// 添加参数
dbus_uint32_t a = 10, b = 20;
if (!dbus_message_append_args(message,
                            DBUS_TYPE_UINT32, &a,
                            DBUS_TYPE_UINT32, &b,
                            DBUS_TYPE_INVALID)) {
    fprintf(stderr, "添加参数失败\n");
    dbus_message_unref(message);
    return;
}

// 发送并等待回复
DBusError error;
dbus_error_init(&error);
DBusMessage *reply = dbus_connection_send_with_reply_and_block(
    connection, message, 1000, &timeout, &error  // 1秒超时
);

if (dbus_error_is_set(&error)) {
    fprintf(stderr, "调用失败: %s\n", error.message);
    dbus_error_free(&error);
} else if (reply) {
    // 处理回复...
    dbus_message_unref(reply);
}

dbus_message_unref(message);

示例3:调用设置属性值的方法

// 设置音量:SetVolume(0.8)
DBusMessage *message = dbus_message_new_method_call(
    "org.mpris.MediaPlayer2.vlc",
    "/org/mpris/MediaPlayer2",
    "org.freedesktop.DBus.Properties",
    "Set"  // 标准的Properties接口的Set方法
);

if (message) {
    const char *interface = "org.mpris.MediaPlayer2.Player";
    const char *property_name = "Volume";
    double volume = 0.8;
    
    DBusMessageIter iter, sub;
    dbus_message_iter_init_append(message, &iter);
    
    // 参数是:接口名,属性名,属性值
    dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &interface);
    dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &property_name);
    
    // 属性值需要包装为variant类型
    dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT, "d", &sub);
    dbus_message_iter_append_basic(&sub, DBUS_TYPE_DOUBLE, &volume);
    dbus_message_iter_close_container(&iter, &sub);
    
    // 发送消息...
    dbus_connection_send(connection, message, NULL);
    dbus_message_unref(message);
}

 

核心概念

dbus_message_new_method_call 是用于创建一个D-Bus方法调用消息的函数。简单来说,它就是用来构造一个"请求包",让你能够调用另一个D-Bus服务提供的方法

可以把D-Bus通信想象成远程过程调用(RPC):

  • 服务端:提供各种方法(比如 PlayPauseGetVolume

  • 客户端:需要调用这些方法

  • dbus_message_new_method_call:就是客户端用来"写调用请求"的工具


函数原型

c
 
 
DBusMessage * dbus_message_new_method_call(const char *service,
                                          const char *path,
                                          const char *interface,
                                          const char *method);

参数详解

这四个参数共同确定了"要调用谁的方法":

  1. service (const char *)

    • 目标服务的众所周知名称。这就是对方通过 dbus_bus_request_name 注册的名称。

    • 示例"org.mpris.MediaPlayer2.vlc""com.example.CalculatorService"

  2. path (const char *)

    • 对象路径。在D-Bus中,一个服务可以暴露多个对象,每个对象有唯一的路径,类似于文件系统路径。

    • 示例"/org/mpris/MediaPlayer2""/com/example/Calculator"

    • 通常以反向DNS格式组织。

  3. interface (const char *)

    • 接口名称。一个对象可以实现多个接口,每个接口包含一组相关的方法和信号。

    • 示例"org.mpris.MediaPlayer2.Player""com.example.Calculator.Basic"

    • 这相当于编程中的接口或类名。

  4. method (const char *)

    • 要调用的具体方法名

    • 示例"Play""Pause""Add""GetProperty"


返回值

  • 成功:返回一个指向新创建的 DBusMessage 对象的指针。

  • 失败:返回 NULL(通常是因为内存不足)。

重要:返回的消息对象已经过引用计数,使用完后必须用 dbus_message_unref 释放。

posted @ 2025-11-06 03:22  FBshark  阅读(21)  评论(0)    收藏  举报