当前位置: 首页 > 工具软件 > DBus > 使用案例 >

DBus学习

宋宇
2023-12-01

背景介绍

DBus是什么

​ DBus(Desktop Bus)是一种跨进程通信机制,提供了不同进程之间进行通信的能力。它的设计旨在提供一种简单、高效、安全的通信方式,使得增加新的软件组件变得更加容易,并且能够轻松地维护现有的组件。DBus通信机制被广泛应用于Linux操作系统和桌面环境中,如GNOME、KDE等桌面环境。DBus还提供了一些重要的通信功能,这些功能在一些Linux发行版、应用程序等中非常常见,例如,开机提示、系统监控、命名服务等。

DBus的发展历史

​ DBus(Desktop Bus)是一个在Linux和其他类Unix操作系统中使用的系统总线,用于进程间通信和设备插入/拔出通知。
DBus最早是由Red Hat公司的开发人员在2002年-2003年之间创建的,最初是为了解决在GNOME桌面环境中横跨多个进程和应用程序实现通信和设备管理的问题。
​ 2003年,DBus被引入D-BUS 0.23版本中,并成为Freedesktop.org项目的一部分。2006年,DBus 1.0版发布,这是一个重要的版本,它引入了一些新特性和API,并增加了平台支持的广泛性。此后,DBus的更新一直继续,新版本不断增加新功能,解决Bug和安全问题,并提高性能。
​ 今天,DBus已被广泛采用,并成为Linux及其他类Unix操作系统中的标准通信机制,受到许多桌面环境、应用程序和设备管理器的使用。同时,DBus的专业性质使得该技术被云计算、大数据、物联网等领域越来越广泛地运用。

DBus的重要性

​ DBus(Desktop Bus)是一个在Linux和其他类Unix操作系统中使用的系统总线,用于进程间通信和设备插入/拔出通知。DBus的重要性在以下几个方面:

  • 提供了进程间通信的标准机制:DBus提供了一种标准的、可靠的机制来进行进程间通信,使得不同应用程序可以相互通信和协作,从而使得整个系统更加智能化和高效化。

  • 跨平台支持:DBus支持多种类Unix操作系统,包括Linux,FreeBSD,Solaris等,使得DBus可以作为跨平台的进程间通信机制来使用。

  • 设备管理:DBus可以用于设备管理,当用户插入或拔出设备时,DBus会自动检测并发送通知给相关应用程序,从而使得应用程序可以根据设备的状态来正确地响应用户的操作。

  • 代码重用:DBus提供了多种程序语言的绑定,包括C++,Python等,使得DBus可以快速地集成到现有系统中,并且减少开发时间和成本。

    总之,DBus的重要性不仅在于提供了进程间通信的标准机制,还在于多方面的适应性和可靠性,使得DBus成为Linux及其他类Unix操作系统中的标准通信机制,并且被广泛采用于各种应用程序和设备管理器中。

Dbus的资料

应用场景

  • 操作系统: DBus可以在操作系统内部实现不同进程间的消息传递和数据交换。例如,Linux中的systemd就使用DBus来管理各个系统服务之间的通讯和信息交互。

  • 消息总线: 在DBus消息总线中,各个组件可以以客户端-服务端的方式一起工作。DBus服务可以在总线上注册自己提供的服务,客户端则可以使用DBus总线查询和调用这些服务。DBus采用基于总线广播的方式,将服务和请求发送到相应的组件,这样就可以实现组件之间的通信。

  • 框架和应用程序之间的通信:DBus可以作为框架和应用程序之间通信的抽象层,提供了统一的接口和协议,使得应用程序能够使用DBus实现与框架之间的通信。例如,Gnome桌面环境中,DBus被广泛应用,用于各个应用程序的交互,例如通知、系统状态、文件管理等。

  • 远程通信:通过DBus的远程通信,可以允许客户端程序通过DBus连接到远程服务器上的DBus,并向服务器发送请求以获取所需的服务。DBus消息传递机制可用于传递标准和自定义消息,从而实现不同的通信需求。

通信类型

  • 消息总线(Message Bus):DBus通过在消息总线上发布和订阅消息的方式实现组件之间的通信。总线是一个中央的消息处理器,组件可以将消息发送到总线上,总线根据消息内容将其路由到订阅了该消息的组件中。DBus采用基于广播的方式,支持点到点和广播通信。

  • 发送接收(Send-Reveice):DBus还支持一对一的点对点通信模式,即发送接收模式。在这种模式下,组件可以直接向其他组件发送消息或接收其他组件发送的消息,而不必使用DBus总线。

  • 远程调用(Remote Procedure Calls,RPC):DBus还支持远程调用,即可以在不同的计算机或者进程之间进行远程过程调用。DBus使用的RPC机制类似于本地的函数调用,使得开发者可以像本地函数调用那样进行远程函数调用,从而在分布式系统中实现服务调用。

    总之,DBus通过支持消息总线、点对点通信和远程调用来实现组件间的通信。消息总线是DBus最常用的通信模式,采用基于总线广播的方式,将消息从发送者路由到接收者。DBus发送接收模式则针对一对一的点对点通信而设计,而DBus的RPC机制则是用于在分布式系统中进行远程函数调用。

API及使用

​ DBus API是DBus提供给应用程序和组件使用的一系列API,它们使得DBus消息总线可以方便地被集成到应用程序或组件中,以实现高效的通信。DBus API通常包括C和Python两种编程语言接口。

DBus C API:

DBus C API是DBus的C语言编程接口,DBus C API支持通信(实现客户端和服务器的DBus连接)、处理错误和注册/注销服务等功能。DBus C API提供以下常用的函数:

  1. dbus_connection_send():发送DBus消息。
  2. dbus_message_new_method_call():创建用于DBus方法调用的消息。
  3. dbus_bus_get():获取DBus总线连接。
  4. dbus_connection_add_filter():向DBus连接添加过滤器。

DBus Python API:

DBus Python API是DBus的Python语言编程接口,DBus Python API提供Python接口来支持DBus通信。DBus Python API包括dbus、dbus.service、dbus.mainloop和dbus.types等模块,DBus Python API提供以下常用的类和方法:

  1. dbus.SessionBus():打开会话DBus总线连接。
  2. dbus.Interface():DBus接口的Python封装器。
  3. dbus.service.Object():用于实现DBus对象的Python类。
  4. dbus.mainloop.glib.DBusGMainLoop():将DBus事件循环整合到GLib中。

通信步骤

使用DBus API进行DBus通信的过程通常包括以下步骤:

  1. 创建DBus连接:使用DBus C API或者DBus Python API创建DBus连接。
  2. 发送DBus消息:使用DBus C API或DBus Python API发送DBus消息。
  3. 接收DBus消息:使用DBus C API或DBus Python API来接收DBus消息。
  4. 处理DBus消息:使用DBus C API或DBus Python API来解析DBus消息,并根据消息类型处理DBus消息。

总之,DBus API能够提供简单易用的接口,使得DBus在应用程序和组件中的集成变得简单和快速。使用DBus API可以实现高效的DBus通信,从而提高了应用程序和组件的通信效率和质量。可运行代码

dbus c关键接口

DBusConnection *dbus_bus_get (DBusBusType type, DBusError *error); /* 建立和总线的连接 */

int dbus_bus_request_name (DBusConnection *connection,
                           const char *name,
                           unsigned int flags,
                           DBusError *error); /* 注册连接名称 */

DBusMessage *dbus_message_new_signal (const char *path,
                                      const char *iface,
                                      const char *name); /* 创建信号类型消息*/

void dbus_message_iter_init_append ( DBusMessage *message,
                                    DBusMessageIter *iter); /* 加入参数到信号 */

dbus_bool_t dbus_connection_send ( DBusConnection *connection,
                                  DBusMessage *message,
                                  dbus_uint32_t *serial); /* 发送信号到总线 */

void dbus_message_unref (DBusMessage *message); /* 释放消息 */

void dbus_bus_add_match ( DBusConnection *connection,
                         const char *rule,
                         DBusError *error); /* 请求获取调用消息 */

DBusMessage *dbus_connection_pop_message ( DBusConnection *connection); /* 从总线获取消息 */

dbus_bool_t dbus_message_is_method_call (DBusMessage *message,
                                         const char *iface,
                                         const char *method); /* 判定消息是方法调用 */

dbus_bool_t dbus_message_iter_init (DBusMessage *message,
                                                    DBusMessageIter *iter); /* 获取参数 */

DBusMessage *dbus_message_new_method_return (DBusMessage *method_call) /* 创建返回消息 */

                    void dbus_message_iter_init_append ( DBusMessage *message,
                                                    DBusMessageIter *iter); /* 在消息中填入参数 */

dbus_bool_t dbus_connection_send ( DBusConnection *connection,
                                                  DBusMessage *message,
                                                  dbus_uint32_t *serial); /* 发送返回消息 */

DBusMessage *dbus_message_new_method_call (const char *destination,
                                                           const char *path,
                                                           const char *iface,
                                                           const char *method); /* 创建一个函数调用消息 */

void dbus_message_iter_init_append (DBusMessage *message,
                                                    DBusMessageIter *iter); /* 为消息添加参数 */

dbus_bool_t dbus_connection_send_with_reply (DBusConnection *connection,
                                                             DBusMessage *message,
                                                             DBusPendingCall **pending_return,
                                                             int timeout_milliseconds); /* 发送消息 */

void dbus_pending_call_block (DBusPendingCall *pending); /* 阻塞等待返回值 */

DBusMessage *dbus_pending_call_steal_reply (DBusPendingCall *pending); /* 获得返回消息 */

信号和方法调用

一个信号监听的示例

监听信号:

#include <glib.h>
#include <dbus/dbus-glib.h>
#include <dbus/dbus.h>

static gboolean send_ping (DBusConnection *bus);

int main (int argc, char **argv)
{
  GMainLoop *loop;
  DBusConnection *bus;
  DBusError error;

  /* Create a new event loop to run in */
  loop = g_main_loop_new (NULL, FALSE);

  /* Get a connection to the session bus */
  dbus_error_init (&error);
  bus = dbus_bus_get (DBUS_BUS_SESSION, &error);
  if (!bus) {
    g_warning ("Failed to connect to the D-BUS daemon: %s", error.message);
    dbus_error_free (&error);
    return 1;
  }

  /* Set up this connection to work in a GLib event loop */
  dbus_connection_setup_with_g_main (bus, NULL);
  /* Every second call send_ping() with the bus as an argument*/
  g_timeout_add (1000, (GSourceFunc)send_ping, bus);

  /* Start the event loop */
  g_main_loop_run (loop);
  return 0;
}

static gboolean
send_ping (DBusConnection *bus)
{
  DBusMessage *message;

  /* Create a new signal "Ping" on the "com.burtonini.dbus.Signal" interface,
   * from the object "/com/burtonini/dbus/ping". */
  message = dbus_message_new_signal ("/com/burtonini/dbus/ping",
                                     "com.burtonini.dbus.Signal", "Ping");
  /* Append the string "Ping!" to the signal */
  const char *ping = "Ping!";
  dbus_message_append_args (message,
                            DBUS_TYPE_STRING, &ping,
                            DBUS_TYPE_INVALID);
  /* Send the signal */
  dbus_connection_send (bus, message, NULL);
  /* Free the signal now we have finished with it */
  dbus_message_unref (message);
  /* Tell the user we send a signal */
  g_print("Ping!\n");
  /* Return TRUE to tell the event loop we want to be called again */
  return TRUE;
}

发送信号

#include <glib.h>
#include <dbus/dbus-glib.h>
#include <dbus/dbus.h>

static gboolean send_ping (DBusConnection *bus);

int
main (int argc, char **argv)
{
  GMainLoop *loop;
  DBusConnection *bus;
  DBusError error;

  /* Create a new event loop to run in */
  loop = g_main_loop_new (NULL, FALSE);

  /* Get a connection to the session bus */
  dbus_error_init (&error);
  bus = dbus_bus_get (DBUS_BUS_SESSION, &error);
  if (!bus) {
    g_warning ("Failed to connect to the D-BUS daemon: %s", error.message);
    dbus_error_free (&error);
    return 1;
  }

  /* Set up this connection to work in a GLib event loop */
  dbus_connection_setup_with_g_main (bus, NULL);
  /* Every second call send_ping() with the bus as an argument*/
  g_timeout_add (1000, (GSourceFunc)send_ping, bus);

  /* Start the event loop */
  g_main_loop_run (loop);
  return 0;
}

static gboolean
send_ping (DBusConnection *bus)
{
  DBusMessage *message;

  /* Create a new signal "Ping" on the "com.burtonini.dbus.Signal" interface,
   * from the object "/com/burtonini/dbus/ping". */
  message = dbus_message_new_signal ("/com/burtonini/dbus/ping",
                                     "com.burtonini.dbus.Signal", "Ping");
  /* Append the string "Ping!" to the signal */
  const char *ping = "Ping!";
  dbus_message_append_args (message,
                            DBUS_TYPE_STRING, &ping,
                            DBUS_TYPE_INVALID);
  /* Send the signal */
  dbus_connection_send (bus, message, NULL);
  /* Free the signal now we have finished with it */
  dbus_message_unref (message);
  /* Tell the user we send a signal */
  g_print("Ping!\n");
  /* Return TRUE to tell the event loop we want to be called again */
  return TRUE;
}

有关于信号和方法调用的

服务端:

#include <stdbool.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <dbus/dbus.h>
#include <dbus/dbus-glib-lowlevel.h> /* for glib main loop */

const char *version = "0.1";
GMainLoop *mainloop;

/*
 * This is the XML string describing the interfaces, methods and
 * signals implemented by our 'Server' object. It's used by the
 * 'Introspect' method of 'org.freedesktop.DBus.Introspectable'
 * interface.
 *
 * Currently our tiny server implements only 3 interfaces:
 *
 *    - org.freedesktop.DBus.Introspectable
 *    - org.freedesktop.DBus.Properties
 *    - org.example.TestInterface
 *
 * 'org.example.TestInterface' offers 3 methods:
 *
 *    - Ping(): makes the server answering the string 'Pong'.
 *              It takes no arguments.
 *
 *    - Echo(): replies the passed string argument.
 *
 *    - EmitSignal(): send a signal 'OnEmitSignal'
 *
 *    - Quit(): makes the server exit. It takes no arguments.
 */
const char *server_introspection_xml =
    DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE
    "<node>\n"

    "  <interface name='org.freedesktop.DBus.Introspectable'>\n"
    "    <method name='Introspect'>\n"
    "      <arg name='data' type='s' direction='out' />\n"
    "    </method>\n"
    "  </interface>\n"

    "  <interface name='org.freedesktop.DBus.Properties'>\n"
    "    <method name='Get'>\n"
    "      <arg name='interface' type='s' direction='in' />\n"
    "      <arg name='property'  type='s' direction='in' />\n"
    "      <arg name='value'     type='s' direction='out' />\n"
    "    </method>\n"
    "    <method name='GetAll'>\n"
    "      <arg name='interface'  type='s'     direction='in'/>\n"
    "      <arg name='properties' type='a{sv}' direction='out'/>\n"
    "    </method>\n"
    "  </interface>\n"

    "  <interface name='org.example.TestInterface'>\n"
    "    <property name='Version' type='s' access='read' />\n"
    "    <method name='Ping' >\n"
    "      <arg type='s' direction='out' />\n"
    "    </method>\n"
    "    <method name='Echo'>\n"
    "      <arg name='string' direction='in' type='s'/>\n"
    "      <arg type='s' direction='out' />\n"
    "    </method>\n"
    "    <method name='EmitSignal'>\n"
    "    </method>\n"
    "    <method name='Quit'>\n"
    "    </method>\n"
    "    <signal name='OnEmitSignal'>\n"
    "    </signal>"
    "  </interface>\n"

    "</node>\n";

/*
 * This implements 'Get' method of DBUS_INTERFACE_PROPERTIES so a
 * client can inspect the properties/attributes of 'TestInterface'.
 */
DBusHandlerResult server_get_properties_handler(const char *property, DBusConnection *conn, DBusMessage *reply)
{
    if (!strcmp(property, "Version"))
    {
        dbus_message_append_args(reply,
                                 DBUS_TYPE_STRING, &version,
                                 DBUS_TYPE_INVALID);
    }
    else
        /* Unknown property */
        return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;

    if (!dbus_connection_send(conn, reply, NULL))
        return DBUS_HANDLER_RESULT_NEED_MEMORY;
    return DBUS_HANDLER_RESULT_HANDLED;
}

/*
 * This implements 'GetAll' method of DBUS_INTERFACE_PROPERTIES. This
 * one seems required by g_dbus_proxy_get_cached_property().
 */
DBusHandlerResult server_get_all_properties_handler(DBusConnection *conn, DBusMessage *reply)
{
    DBusHandlerResult result;
    DBusMessageIter array, dict, iter, variant;
    const char *property = "Version";

    /*
     * All dbus functions used below might fail due to out of
     * memory error. If one of them fails, we assume that all
     * following functions will fail too, including
     * dbus_connection_send().
     */
    result = DBUS_HANDLER_RESULT_NEED_MEMORY;

    dbus_message_iter_init_append(reply, &iter);
    dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "{sv}", &array);

    /* Append all properties name/value pairs */
    property = "Version";
    dbus_message_iter_open_container(&array, DBUS_TYPE_DICT_ENTRY, NULL, &dict);
    dbus_message_iter_append_basic(&dict, DBUS_TYPE_STRING, &property);
    dbus_message_iter_open_container(&dict, DBUS_TYPE_VARIANT, "s", &variant);
    dbus_message_iter_append_basic(&variant, DBUS_TYPE_STRING, &version);
    dbus_message_iter_close_container(&dict, &variant);
    dbus_message_iter_close_container(&array, &dict);

    dbus_message_iter_close_container(&iter, &array);

    if (dbus_connection_send(conn, reply, NULL))
        result = DBUS_HANDLER_RESULT_HANDLED;
    return result;
}

/*
 * This function implements the 'TestInterface' interface for the
 * 'Server' DBus object.
 *
 * It also implements 'Introspect' method of
 * 'org.freedesktop.DBus.Introspectable' interface which returns the
 * XML string describing the interfaces, methods, and signals
 * implemented by 'Server' object. This also can be used by tools such
 * as d-feet(1) and can be queried by:
 *
 * $ gdbus introspect --session --dest org.example.TestServer --object-path /org/example/TestObject
 */
DBusHandlerResult server_message_handler(DBusConnection *conn, DBusMessage *message, void *data)
{
    DBusHandlerResult result;
    DBusMessage *reply = NULL;
    DBusError err;
    bool quit = false;

    fprintf(stderr, "Got D-Bus request: %s.%s on %s\n",
            dbus_message_get_interface(message),
            dbus_message_get_member(message),
            dbus_message_get_path(message));

    /*
     * Does not allocate any memory; the error only needs to be
     * freed if it is set at some point.
     */
    dbus_error_init(&err);

    if (dbus_message_is_method_call(message, DBUS_INTERFACE_INTROSPECTABLE, "Introspect"))
    {

        if (!(reply = dbus_message_new_method_return(message)))
            goto fail;

        dbus_message_append_args(reply,
                                 DBUS_TYPE_STRING, &server_introspection_xml,
                                 DBUS_TYPE_INVALID);
    }
    else if (dbus_message_is_method_call(message, DBUS_INTERFACE_PROPERTIES, "Get"))
    {
        const char *interface, *property;

        if (!dbus_message_get_args(message, &err,
                                   DBUS_TYPE_STRING, &interface,
                                   DBUS_TYPE_STRING, &property,
                                   DBUS_TYPE_INVALID))
            goto fail;

        if (!(reply = dbus_message_new_method_return(message)))
            goto fail;

        result = server_get_properties_handler(property, conn, reply);
        dbus_message_unref(reply);
        return result;
    }
    else if (dbus_message_is_method_call(message, DBUS_INTERFACE_PROPERTIES, "GetAll"))
    {

        if (!(reply = dbus_message_new_method_return(message)))
            goto fail;

        result = server_get_all_properties_handler(conn, reply);
        dbus_message_unref(reply);
        return result;
    }
    else if (dbus_message_is_method_call(message, "org.example.TestInterface", "Ping"))
    {
        const char *pong = "Pong";

        if (!(reply = dbus_message_new_method_return(message)))
            goto fail;

        dbus_message_append_args(reply,
                                 DBUS_TYPE_STRING, &pong,
                                 DBUS_TYPE_INVALID);
    }
    else if (dbus_message_is_method_call(message, "org.example.TestInterface", "Echo"))
    {
        const char *msg;

        if (!dbus_message_get_args(message, &err,
                                   DBUS_TYPE_STRING, &msg,
                                   DBUS_TYPE_INVALID))
            goto fail;

        if (!(reply = dbus_message_new_method_return(message)))
            goto fail;

        dbus_message_append_args(reply,
                                 DBUS_TYPE_STRING, &msg,
                                 DBUS_TYPE_INVALID);
    }
    else if (dbus_message_is_method_call(message, "org.example.TestInterface", "EmitSignal"))
    {

        if (!(reply = dbus_message_new_signal("/org/example/TestObject",
                                              "org.example.TestInterface",
                                              "OnEmitSignal")))
            goto fail;

        if (!dbus_connection_send(conn, reply, NULL))
            return DBUS_HANDLER_RESULT_NEED_MEMORY;

        /* Send a METHOD_RETURN reply. */
        reply = dbus_message_new_method_return(message);
    }
    else if (dbus_message_is_method_call(message, "org.example.TestInterface", "Quit"))
    {
        /*
         * Quit() has no return values but a METHOD_RETURN
         * reply is required, so the caller will know the
         * method was successfully processed.
         */
        reply = dbus_message_new_method_return(message);
        quit = true;
    }
    else
        return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;

fail:
    if (dbus_error_is_set(&err))
    {
        if (reply)
            dbus_message_unref(reply);
        reply = dbus_message_new_error(message, err.name, err.message);
        dbus_error_free(&err);
    }

    /*
     * In any cases we should have allocated a reply otherwise it
     * means that we failed to allocate one.
     */
    if (!reply)
        return DBUS_HANDLER_RESULT_NEED_MEMORY;

    /* Send the reply which might be an error one too. */
    result = DBUS_HANDLER_RESULT_HANDLED;
    if (!dbus_connection_send(conn, reply, NULL))
        result = DBUS_HANDLER_RESULT_NEED_MEMORY;
    dbus_message_unref(reply);

    if (quit)
    {
        fprintf(stderr, "Server exiting...\n");
        g_main_loop_quit(mainloop);
    }
    return result;
}

const DBusObjectPathVTable server_vtable = {
    .message_function = server_message_handler};

int main(void)
{
    DBusConnection *conn;
    DBusError err;
    int rv;

    dbus_error_init(&err);

    /* connect to the daemon bus */
    conn = dbus_bus_get(DBUS_BUS_SESSION, &err);
    if (!conn)
    {
        fprintf(stderr, "Failed to get a session DBus connection: %s\n", err.message);
        goto fail;
    }

    rv = dbus_bus_request_name(conn, "org.example.TestServer", DBUS_NAME_FLAG_REPLACE_EXISTING, &err);
    if (rv != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER)
    {
        fprintf(stderr, "Failed to request name on bus: %s\n", err.message);
        goto fail;
    }

    if (!dbus_connection_register_object_path(conn, "/org/example/TestObject", &server_vtable, NULL))
    {
        fprintf(stderr, "Failed to register a object path for 'TestObject'\n");
        goto fail;
    }

    /*
     * For the sake of simplicity we're using glib event loop to
     * handle DBus messages. This is the only place where glib is
     * used.
     */
    printf("Starting dbus tiny server v%s\n", version);
    mainloop = g_main_loop_new(NULL, false);
    /* Set up the DBus connection to work in a GLib event loop */
    dbus_connection_setup_with_g_main(conn, NULL);
    /* Start the glib event loop */
    g_main_loop_run(mainloop);

    return EXIT_SUCCESS;
fail:
    dbus_error_free(&err);
    return EXIT_FAILURE;
}

客户端

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dbus/dbus-glib.h>
#include <dbus/dbus.h>
#include <unistd.h>
// 建立与session D-Bus daemo的连接,并设定连接的名字,相关的代码已经多次使用过了
DBusConnection *connect_dbus()
{
    DBusError err;
    DBusConnection *connection;
    int ret;

    // Step 1: connecting session bus
    /* initialise the erroes */
    dbus_error_init(&err);
    /* Connect to Bus*/
    connection = dbus_bus_get(DBUS_BUS_SESSION, &err);
    if (dbus_error_is_set(&err))
    {
        fprintf(stderr, "Connection Err : %s/n", err.message);
        dbus_error_free(&err);
    }
    if (connection == NULL)
        return NULL;

    // step 2: 设置BUS name,也即连接的名字。
    ret = dbus_bus_request_name(connection, "test.wei.source", 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, char *param)
{
    DBusError err;
    DBusMessage *msg;
    DBusMessageIter arg;
    DBusPendingCall *pending;
    dbus_bool_t *stat;
    dbus_uint32_t *level;

    dbus_error_init(&err);

    // 针对目的地地址,请参考图,创建一个method call消息。 Constructs a new message to invoke a method on a remote object.
    msg = dbus_message_new_method_call("org.example.TestServer", "/org/example/TestObject", "org.example.TestInterface", "Echo");
    if (msg == NULL)
    {
        g_printerr("Message NULL");
        return;
    }

    // 为消息添加参数。Append arguments
    dbus_message_iter_init_append(msg, &arg);
    if (!dbus_message_iter_append_basic(&arg, DBUS_TYPE_STRING, &param))
    {
        g_printerr("Out of Memory!");
        exit(1);
    }

    // 发送消息并获得reply的handle 。Queues a message to send, as with dbus_connection_send() , but also returns a DBusPendingCall used to receive a reply to the message.
    if (!dbus_connection_send_with_reply(connection, msg, &pending, -1))
    {
        g_printerr("Out of Memory!");
        exit(1);
    }

    if (pending == NULL)
    {
        g_printerr("Pending Call NULL: connection is disconnected ");
        dbus_message_unref(msg);
        return;
    }

    dbus_connection_flush(connection);
    dbus_message_unref(msg);

    // waiting a reply,在发送的时候,已经获取了method reply的handle,类型为DBusPendingCall。
    //  block until we recieve a reply, Block until the pending call is completed.
    dbus_pending_call_block(pending);
    // get the reply message,Gets the reply, or returns NULL if none has been received yet.
    msg = dbus_pending_call_steal_reply(pending);
    if (msg == NULL)
    {
        fprintf(stderr, "Reply Null/n");
        exit(1);
    }
    // free the pending message handle
    dbus_pending_call_unref(pending);
    // read the parameters
    if (!dbus_message_iter_init(msg, &arg))
        fprintf(stderr, "Message has no arguments!/n");
    // else if (dbus_message_iter_get_arg_type(&arg) != DBUS_TYPE_BOOLEAN)
    //     fprintf(stderr, "Argument is not boolean!/n");
    // else
    //     dbus_message_iter_get_basic(&arg, &stat);

    ///
    if (dbus_message_iter_get_arg_type(&arg) == DBUS_TYPE_STRING)
    {
        const char *value;
        dbus_message_iter_get_basic(&arg, &value);
        printf("Method call response returned string \"%s\".\n", value);
    }
    else
    {
        // 返回类型不正确
        g_error("Error: unexpected return type from method call.");
    }
    ///

    // if (!dbus_message_iter_next(&arg))
    //     fprintf(stderr, "Message has too few arguments!/n");
    // else if (dbus_message_iter_get_arg_type(&arg) != DBUS_TYPE_UINT32)
    //     fprintf(stderr, "Argument is not int!/n");
    // else
    //     dbus_message_iter_get_basic(&arg, &level);

    // printf("Got Reply: %d, %d/n", stat, level);
    dbus_message_unref(msg);
}

int main(int argc, char **argv)
{
    DBusConnection *connection;
    connection = connect_dbus();
    if (connection == NULL)
        return -1;

    send_a_method_call(connection, "Hello, D-Bus");
    return 0;
}

其他说明

dbus-damon 配置

dbus-daemon --config-file=/overlay/debug-allow-all.conf --fork --print-address

配置内容如:

<!-- Bus that listens on a debug pipe and doesn't create any restrictions -->

<!DOCTYPE busconfig PUBLIC "-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"
"http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
<busconfig>
<type>session</type>

<listen>unix:tmpdir=/tmp</listen>

<standard_session_servicedirs />

<policy context="default">
<!-- Allow everything to be sent -->
<allow send_destination="*" eavesdrop="true"/>
<!-- Allow everything to be received -->
<allow eavesdrop="true"/>
<!-- Allow anyone to own anything -->
<allow own="*"/>
<allow user="*"/>
</policy>

</busconfig>

添加环境变量

export DBUS_SESSION_BUS_ADDRESS=unix:abstract=/tmp/dbus-W1ALCK2LKH,guid=c3b18510d26f9a9231d849800000411f

dbus-send使用

列出所有总线接口

dbus-send --session  --dest=org.freedesktop.DBus   --type=method_call   --print-reply   /org/freedesktop/DBus   org.freedesktop.DBus.ListNames

查看对方总线所支持的对象接口

dbus-send --session --type=method_call 	--print-reply 	--dest=org.freedesktop.DBus / org.freedesktop.DBus.Introspectable.Introspect

发送信号

如果你要通过 dbus-send 命令发送字符串类型的信号,需要使用 –dest 参数指定目标程序和对象。下面是一个发送字符串类型信号的例子:

dbus-send --session --type=signal --dest=com.example.SomeService /com/example/SomeObject com.example.SomeInterface.SomeSignal string:"hello world"

这个命令的具体解释如下:

  • –dest=com.example.SomeService 参数表示要发送消息的目标程序,com.example.SomeService 是目标程序的名称;
  • /com/example/SomeObject 表示要发送消息的对象路径;
  • com.example.SomeInterface.SomeSignal 表示要发送的信号的名称;
  • string:“hello world” 表示要发送的字符串类型的参数,本例中是发送了字符串 “hello world”

如果信号的参数是其他数据类型,可以使用不同的参数类型指定参数的类型。例如,如果要发送一个整数类型的参数,可以使用下面的命令:

dbus-send --session --type=signal --dest=com.example.SomeService /com/example/SomeObject com.example.SomeInterface.SomeSignal int32:123

这个命令的意思是向目标程序 com.example.SomeService 的对象路径 /com/example/SomeObject 发送名为 com.example.SomeInterface.SomeSignal 的信号,该信号包含一个 32 位的整数参数,值为 123

dbus-send --session --type=method_call --print-reply --dest=org.example.TestServer  /org/example/TestObject org.example.TestInterface.Ping
---
dbus-send --session --type=method_call --print-reply --dest=org.example.TestServer  /org/example/TestObject org.example.TestInterface.Echo string:"Ping"
 类似资料: