한국어
오픈소스포럼
 이곳은 다양한 오픈소스 프로젝트를 소개하고 리뷰, 활용 방법을 공유합니다.

GDBus 튜토리얼(GDBus tutorial)

makersweb 2019.06.30 00:02 조회 수 : 10214

이 글은 간단한 예제를 통해 GDBus사용법을 설명한다.

 

GDBus는 GLib에 포함되어 제공되므로 먼저 관련 개발 패키지를 설치해야한다.

참고로 GLib은 GTK+ 프로젝트의 일부로 시작되었으며 비 GUI 적인 크로스 플랫폼 소프트웨어 유틸리티 세트이다. 플랫폼에 독립적인 응용프로그램을 만들 수 있도록 API를 제공한다.

https://developer.gnome.org/glib/

 

GIO는 다음의 Low-level D-Bus API 및

D-Bus Utilities — Various utilities related to D-Bus

D-Bus Addresses — D-Bus connection endpoints

D-Bus Introspection Data — Node and interface description data structures

GDBusError — Mapping D-Bus errors to and from GError

GDBusMessage — D-Bus Message

GDBusConnection — D-Bus Connections

GDBusMethodInvocation — Object for handling remote calls

GDBusServer — Helper for accepting connections

GDBusAuthObserver — Object used for authenticating connections

 

Highlevel D-Bus API를 제공한다.

Owning Bus Names — Simple API for owning bus names

Watching Bus Names — Simple API for watching bus names

GDBusInterface — Base type for D-Bus interfaces

GDBusInterfaceSkeleton — Service-side D-Bus interface

GDBusProxy — Client-side D-Bus interface proxy

GDBusObject — Base type for D-Bus objects

GDBusObjectSkeleton — Service-side D-Bus object

GDBusObjectProxy — Client-side D-Bus object

GDBusObjectManager — Base type for D-Bus object managers

GDBusObjectManagerServer — Service-side object manager

GDBusObjectManagerClient — Client-side object manager

 

간단한 예제를 통해 익혀보자.

 

운영체제: Linux(Ubuntu18.04)

IDE: QtCreator

 

아래의 명령으로 패키지를 설치할 수 있다.

sudo apt update

sudo apt install libglib2.0-dev

 

다른 DBus 바인딩과 비슷하게 GDBus도 DBus 인터페이스를 설명하는(객체의 인터페이스, 메소드 및 시그널등) XML형식의 문서 즉, DBus Introspection를 작성한다.

 

간단한 Introspection XML 예제.

net.Makersweb.Media.Playback.xml

<node>
  <interface name="net.Makersweb.Media.Playback">
    <method name="Play">
      <arg name="index" direction="in" type="i"/>
    </method>

    <method name="Pause"></method>

    <method name="Prev"></method>

    <method name="Next"></method>

    <signal name="PlaybackStateChanged">
      <arg name="state" type="i"/>
    </signal>

    <property name="CurrentTrack" type="i" access="read"/>
  </interface>
</node>

 

gdbus-codegen 사용

이 Introspection XML은 gdbus-codegen 을 통해서 D-Bus 인터페이스를위한 클라이언트 및 서버 측 래퍼를 생성할 수 있다.

gdbus-codegen --generate-c-code playback-generated    \
              --c-namespace example                   \
              --interface-prefix net.Makersweb.Media. \
              net.Makersweb.Media.Playback.xml

 

위의 명령줄로 playback-generated.c 와 playback-generated.h 파일이 만들어 진다.

 

다음은 gdbus-codegen 옵션에 대한 간단한 설명이다.

--interface-prefix org.project.Prefix.
모든 D-Bus 인터페이스 이름에서 제거하기위한 접두어.
 
--generate-docbook OUTFILES
Generate Docbook Documentation for each D-Bus interface and put it in OUTFILES-NAME.xml where NAME is a place-holder for the interface name, e.g. net.Corp.FooBar and so on.
 
--generate-c-code OUTFILES
모든 D-Bus 인터페이스에 대한 C 코드를 생성하여 OUTFILES.c 및 OUTFILES.h를 만든다.
 
--c-namespace YourProject
생성 된 C 코드에 사용할 네임 스페이스.
 
--c-generate-object-manager
이 옵션이 전달되면 적합한 GDBusObject, GDBusObjectProxy, GDBusObjectSkeleton 및 GDBusObjectManagerClient 하위 클래스를 생성.
 
--annotate ELEMENT KEY VALUE
지정된 XML 파일에 D-Bus 주석을 삽입하는 데 사용.

 

QtCreator사용

IDE는 QtCreator를 사용하며 다음의 프로젝트파일(.pro)처럼 glib관련 라이브러리를 추가해줘야 한다.

xyz.pro

CONFIG += link_pkgconfig
PKGCONFIG += glib-2.0 gio-2.0 gio-unix-2.0

 

서버측 구현(Server Side)

생성된 playback-generated.h파일을 include하여 랩핑 함수들을 사용한다.

#include "playback-generated.h"

 

mediaplayback.cpp

세션 버스에 이름 등록

MediaPlayback::MediaPlayback()
{
    /* Register bus name */
    m_busId = g_bus_own_name (G_BUS_TYPE_SESSION,
                              "net.Makersweb.Examples.Media",
                              (GBusNameOwnerFlags)(G_BUS_NAME_OWNER_FLAGS_ALLOW_REPLACEMENT | G_BUS_NAME_OWNER_FLAGS_REPLACE),
                              on_bus_acquired,
                              on_name_acquired,
                              nullptr,
                              nullptr,
                              nullptr);
}

 

bus_type에 의해 지정된 버스에서 이름 획득을 시작하고 이름이 획득되면 각각 on_bus_acquired 및 on_name_acquired가 호출된다.

examplePlayback * MediaPlayback::m_obj = nullptr;

void MediaPlayback::on_bus_acquired(GDBusConnection *connection, const gchar *name, gpointer user_data)
{
    g_print ("Acquired a message bus connection\n");

    m_obj = example_playback_skeleton_new();

    example_playback_set_current_track(m_obj, 0);

    /* Handle Play() D-Bus method invocations on the .Playback interface */
    g_signal_connect (m_obj,
                      "handle-play",
                      G_CALLBACK (on_handle_play),
                      nullptr); /* user_data */

    GError *error = nullptr;

    if (!g_dbus_interface_skeleton_export ( G_DBUS_INTERFACE_SKELETON (m_obj),
                                            connection,
                                            "/path/of/dbus_object",
                                            &error))
    {
        /* handle error */
    }
}

 

D-Bus인터페이스 Play()의 콜백함수

gboolean MediaPlayback::on_handle_play(examplePlayback *interface, GDBusMethodInvocation *invocation, gint trackIndex, gpointer user_data)
{
    if(trackIndex >= 0){
        /* Play track Sequence */
        example_playback_set_current_track(m_obj, trackIndex);

        /* D-Bus 메서드 호출 완료 함수 */
        example_playback_complete_play(interface, invocation);
    }
    else {
        g_dbus_method_invocation_return_dbus_error (invocation,
                                                    "Media.Playback.Error.play",
                                                    "invalid track.");
    }

    return TRUE;
}

 

main함수

#include "mediaplayback.h"

gint main (gint argc, gchar *argv[]){
    GMainLoop *loop;
    guint id;

    g_type_init ();

    loop = g_main_loop_new (nullptr, FALSE);

    MediaPlayback * playback = new MediaPlayback;

    g_main_loop_run (loop);

    g_bus_unown_name (id);
    g_main_loop_unref (loop);

    return 0;
}

 

예제: gdbus_server.tar.gz

 

클라이언트측 (Client Side)