1. 程式人生 > >dbus-glib 和 GDBus 的區別

dbus-glib 和 GDBus 的區別

Conceptual differences(概念上的區別)

The central concepts of D-Bus are modelled in a very similar way in dbus-glib and GDBus. Both have a objects representing connections, proxies and method invocations. But there are some important differences:

D-Bus最重要的概念在dbus-glib和GDBus中都是相似的.都用物件表示連線,代理 和 方法執行,但也有一些重要的不同點:

  • dbus-glib uses the libdbus reference implementation, GDBus doesn't. Instead, it relies on GIO streams as transport layer, and has its own implementation for the the D-Bus connection setup and authentication. Apart from using streams as transport, avoiding libdbus also lets GDBus avoid some thorny multithreading issues.

        dbus-glib使用 libdbus reference implementation,GDBus不使用,而是依賴GIO流作為傳輸層,並且擁有一套自己實現的D-Bus連線設定和授權的方法.暫且不說GDBus使用流傳輸,

        不使用libdbus可以使GDBus避免一些多執行緒方面的問題.

  • dbus-glib uses the GObject type system for method arguments and return values, including a homegrown container specialization mechanism. GDBus relies on the 

    GVariant type system which is explicitly designed to match D-Bus types.

       dbus-glib的方法引數和返回值使用Gobject型別系統,其中包含了一個特定結構的自有容器.GDBus依賴專為匹配D-Bus型別而設計的GVariant型別系統.

       dbus-glib 只能提供D-Bus介面,不為物件提供任何型別,

  • The typical way to export an object in dbus-glib involves generating glue code from XML introspection data using dbus-binding-tool. GDBus provides a similar tool called  that can also generate Docbook D-Bus interface documentation.

       dbus-glib中匯出物件的典型方法是使用dbus-binding-tool根據XML內省資料生成程式碼,GDBus也提供了一個類似的工具叫做gdbus-codegen,這個工具也可以生成Docbook D-Bus介面檔案.

  • dbus-glib doesn't provide any convenience API for owning and watching bus names, GDBus provides the g_bus_own_name() and g_bus_watch_name() family of convenience functions.

  • GDBus provides API to parse, generate and work with Introspection XML, dbus-glib doesn't.

        GDBus提供API來解析、生成 和 工作的內省XML,dbus-glib不提供。

Owning bus names

Using dbus-glib, you typically call RequestName manually to own a name, like in the following excerpt:

使用dbus-glib來佔有一個匯流排名字的典型做法是手動呼叫RequestName ,像下面的例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
error = NULL;
res = dbus_g_proxy_call (system_bus_proxy,
                         "RequestName",
                         &error,
                         G_TYPE_STRING, NAME_TO_CLAIM,
                         G_TYPE_UINT,   DBUS_NAME_FLAG_ALLOW_REPLACEMENT,
                         G_TYPE_INVALID,
                         G_TYPE_UINT,   &result,
                         G_TYPE_INVALID);
if (!res)
  {
    if (error != NULL)
      {
        g_warning ("Failed to acquire %s: %s",
                   NAME_TO_CLAIM, error->message);
        g_error_free (error);
      }
    else
      {
        g_warning ("Failed to acquire %s", NAME_TO_CLAIM);
      }
    goto out;
  }

if (result != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER)
  {
    if (error != NULL)
      {
        g_warning ("Failed to acquire %s: %s",
                   NAME_TO_CLAIM, error->message);
        g_error_free (error);
      }
    else
      {
        g_warning ("Failed to acquire %s", NAME_TO_CLAIM

While you can do things this way with GDBus too, using g_dbus_proxy_call_sync(), it is much nicer to use the high-level API for this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
static void
on_name_acquired (GDBusConnection *connection,
                  const gchar     *

Note that g_bus_own_name() works asynchronously and requires you to enter your mainloop to await the on_name_aquired() callback. Also note that in order to avoid race conditions (e.g. when your service is activated by a method call), you have to export your manager object before acquiring the name. The on_bus_acquired() callback is the right place to do such preparations.

需要注意的是g_bus_own_name 工作方式是非同步的,並且需要你進入mainloop來等待on_name_aquired()這個callback被呼叫.還需要注意的是為了防止條件競爭(例如你的服務是同方法呼叫來啟動的),你必須在就on_name_aquired()回撥之前匯出管理物件,on_bus_acquired()這個callback中是匯出管理物件的正確位置.

Creating proxies for well-known names

dbus-glib lets you create proxy objects for well-known names, like the following example:

1
2
3
4
proxy = dbus_g_proxy_new_for_name (system_bus_connection,
                                   "org.freedesktop.Accounts",
                                   "/org/freedesktop/Accounts",
                                   "org.freedesktop.Accounts");

For a DBusGProxy constructed like this, method calls will be sent to the current owner of the name, and that owner can change over time.

The same can be achieved with GDBusProxy:

1
2
3
4
5
6
7
8
9
error = NULL;
proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM,
                                       G_DBUS_PROXY_FLAGS_NONE,
                                       NULL, /* GDBusInterfaceInfo */
                                       "org.freedesktop.Accounts",
                                       "/org/freedesktop/Accounts",
                                       "org.freedesktop.Accounts",
                                       NULL, /* GCancellable */
                                       &error);

For an added layer of safety, you can specify what D-Bus interface the proxy is expected to conform to by using the GDBusInterfaceInfo type. Additionally, GDBusProxy loads, caches and tracks changes to the D-Bus properties on the remote object. It also sets up match rules so D-Bus signals from the remote object are delivered locally.