KDE D-BUS 튜토리얼 ==>
http://techbase.kde.org/index.php?title=Development/Tutorials_(ko)
D-Bus란?
D-Bus는 RPC 프로토콜 혹은 IPC(inter-process communication)시스템으로 설명하며, 데스크탑 응용프로그램과 운영체제의 통신을 위해 만들어졌다. 구조적으로 말하면 몇가지 레이어를 가진다.
- libdbus: 두 응용프로그램 간의 연결 및 메세지 교환을 할 수 있도록 한다.
- message bus daemon 실행 파일: libdbus를 기반으로 하여 제작되었으며 여러개의 응용프로그램에서 연결이 가능하다. 데몬은 응용프로그램으로부터 메세지를 전송받아 다른 응용프로그램으로 전송한다.
- wrapper library or binding: libdbus-glib, libdbus-qt 등 특정 어플리케이션 프레임워크 혹은 파이썬과 같은 언어에 wrapping/binding 가능하다. D-Bus 프로그래밍을 쉽게 할 수 있도록 도와준다. 즉 libdbus는 high-level binding을 위해 low-level backend로 다루어진다고 볼 수 있다. 많은 libdbus api가 binding을 위해 만들어졌다.
libdbus는 오직 one-to-one 연결만 지원하지만 라우터 역할을 하는 message bus daemon과 message를 이용한다면 제약을 극복할 수 있다.
D-Bus 응용
D-Bus는 다음의 두가지 특별한 경우를 위해 디자인되었다.
- 같은 데스크탑 세션안에서 데스크탑 응용프로그램간의 통신 (데스크탑 세션의 통합) - 데스크탑에서는 여러 프로그램들이 동시에 실행된다. 또 서로 통신하기를 원한다. DCOP은 KDE를 위해 만들어졌지만, QT이외에 다른 환경에서는 적용이 힘들다. Bonobo는 GNOME을 위해 만들어졌지만 덩치가 크고, GNOME이외에서는 사용하기 힘들다. D-Bus는 이런 DCOP과 Bonobo를 대체하여 두 데스크탑 환경을 통합하고 좀더 단순한 IPC를 위해 만들어졌다. D-Bus에 대한 의존성을 굉장히 작기 때문에 D-Bus를 사용하고자 하는 다른 응용프로그램들은 걱정할 필요가 없다.
- 데스크탑 세션과 운영체제(Operating System)와의 통신 - 여기서 운영체제라고 하면 커널과 시스템 데몬까지를 포함한다. 에를들어, 디바이스가 연결되었을때, D-Bus는 udev를 가동시킨다. 이것은 데스크탑의 하드웨어와의 더욱 긴밀한 결합을 가져왔다.
다른 IPC 시스템과 구분되는 D-Bus의 장점은 다음과 같다.
- 비동기적으로 사용할 수 있도록 디자인 된 바이너리 프로토콜
- stateful(서버와 클라이언트가 연결하면서 계속 클라이언트와의 상태를 유지하는 것), 신뢰성있는 연결
- message bus 가 daemon 형식
- 구조나 문법등이 DCOP과 흡사하여 KDE에서 사용이 용이함
- 보안 (systemwide mode of message bus)
D-Bus의 개념
D-Bus는 몇가지 버스로 구성된다.
- system bus: 부팅 시간에 시작함. 이 버스는 운영체제와 데몬들에의해 사용됨. 임의의 응용프로그램들이 시스템 이벤트를 spoof하지 못하도록 보안이 되어있음.
- session bus: 사용자 로긴시에 동작함(private). 사용자 응용프로그램에서의 session bus는 통신에 주로 사용된다. 시스템 버스로 부터 메세지를 받을 수 있으며, 반대로 보내는 것에는 제약이 있다.
Objects, Messages, Services의 개념도 알아둘 필요가 있다.
- Objects - D-Bus는 주고 받는 모든 메세지가 소스와 목적지가 있는 peer-to-peer 프로토콜이다. 메세지를 주고 받는데 쓰이는 주소들은 object path로 나타낸다. Objects의 집합을 가진 D-Bus를 사용하는 모든 응용프로그램들에서 메세지들은 어플리케이션이 아닌 특정한 objects로 전달되거나 그것으로 부터 전송받으며 object path로 구분한다. 모든 object들은 하나 혹은 그 이상의 인터페이스를 제공하는데, 인터페이스는 메쏘드 이름의 namespace로 사용되며 단일 object는 여러 메쏘드를 가지고, 메쏘드는 여러 인터페이스를 가진다.
object ---- method 1 ---- interface 1 ---- interface 2 ---- method 2 ---- method 3
- Messages
- header와 body로 구성됨.
- header: message의 meta data. routing information, 데이터(body)의 타입.(네가지 타입의 메세지가 존재함)
- method calls, method returns, signals, errors
- data: type code + data + type code + data ... (type: byte/32bit/64bit integer/doubles/strings)
- Services - D-Bus에서 가장 상위 레벨로 현재 계속적으로 구현중에 있다. 응용프로그램은 버스에 service를 등록할 수 있고, 등록에 성공하면 service를 획득하게 된다. 다른 응용프로그램들은 특정한 service가 버스에 존재하는지 검사할 수 있고 그 service가 아직 시작전이면 시작할 수 있는지 버스에 문의할 수 있다. (org.freedesktop.DBus)
Native Objects 와 Object Paths
java나 python, GObject와 같은 native object를 사용하지 않고, Low-level D-Bus 프로토콜과 libdbus API에서도 native object 대신 object path라는 native object 들을 higher-level binding한것을 제공한다. (/org/kde/kspread/sheets/3/cells/4/5)
Methods 와 Signals
Object들은 두 멤버를 가지는데, method와 signal이다. Method는 Object안에서 발생하는 것이고, signal은 object로 부터 그 object를 주시하고 있는(관계된) 서비스? 들에게 broadcast 되는 것을 말한다.
Interfaces
인터페이스는 method와 signal의 그룹으로 이름이 지어지는데, Glib, Qt, Java에서 사용된다. (org.freedesktop.DBus.Introspectable)
Proxies
다른 프로세스에 있는 (remote) object들이 proxy를 통해 버스의 object에 접근할 수 있다. Proxy를 호출하게 되면 D-Bus는 method 호출, reply message를 기다리고, return value, return from native method.
proxy를 사용하지 않는 경우는 다음과 같이 프로그램할 수 있다.
Message message = new Message("/remote/object/path", "MethodName", arg1, arg2); Connection connection = getBusConnection(); connection.send(message); Message reply = connection.waitForReply(message); if (reply.isError()) { } else { Object returnValue = reply.getReturnValue(); }
Proxy를 사용한 경우
Proxy proxy = new Proxy(getBusConnection(), "/remote/object/path"); Object returnValue = proxy.MethodName(arg1, arg2);
Bus Names
각 응용프로그램들은 bus daemon으로 연결되며 daemon은 unique한 이름을 할당한다. : (콜론)으로 시작되는 bus 이름은 데몬이 살아있는 동안은 재사용되지 않는다. 그것은 응용프로그램으로 부터 같은 이름으로 반복적으로 호출되기 때문이다. 한 예를들면 :34-907 이라고 할당이 되는데, 콜론뒤의 번호는 특별한 의미를 지니지는 않는다.
Addresses
D-Bus의 주소는 서버 측에서는 듣는것으로, 클라이언트에서는 접속하는 용도로 쓰인다. Message bus daemon을 쓰는 경우에는 libdbus는 자동으로 환경변수를 읽어 bus daemon의 주소를 알아온다.
Big Conceptual Picture
Address -> [Bus Name] -> Path -> Interface -> Method
Kernel Event Layer
kernel event layer는 고속의 netlink socket을 사용한 사용자 영역으로의 비동기 kernel-to-user 통신 메카니즘인데, 이 메카니즘은 커널이 D-Bus signal을 보낼 수 있도록 D-Bus에 포함시킬 수 있다.
실행 예
#include <dbus/dbus.h>
DBusError error; DBusConnection *conn; dbus_error_init (&error); conn = dbus_bus_get (DBUS_BUS_SYSTEM, &error); if (!conn) { fprintf (stderr, "%s: %s\n", err.name, err.message); return 1; }
dbus_bus_acquire_service (conn, "org.pirate.parrot", 0, &err); if (dbus_error_is_set (&err)) { fprintf (stderr, "%s: %s\n", err.name, err.message); dbus_connection_disconnect (conn); return; }
DBusMessage *msg; DBusMessageIter iter; /* create a new message of type signal */ msg = dbus_message_new_signal( "org/pirate/parrot/attr", "org.pirate.parrot.attr", "Feathers"); /* build the signal's payload up */ dbus_message_iter_init (msg, &iter); dbus_message_iter_append_string (&iter, "Shiny"); dbus_message_iter_append_string (&iter, "Well Groomed"); /* send the message */ if (!dbus_connection_send (conn, msg, NULL)) fprintf (stderr, "error sending message\n"); /* drop the reference count on the message */ dbus_message_unref (msg); /* flush the connection buffer */ dbus_connection_flush (conn);
if (conn)
dbus_connection_disconnect (conn);
D-BUS API개요
D-BUS 를 이용한 간단한 샘플 프로그램을 확인 후 실제로 사용하는 API 에 대해 알아본다.
API 정리
- DBusServer
- DBusWatchList watchs list : 변수를 read/write 콜백함수가 호출되도록 함 - dbus_watch_handle(watch, flags) 함수 호출시 콜백함수가 동작함.
- DBusTimeoutList timeout : 주기적으로 동작할 함수를 등록함.
- dbus_server_init_base () / dbus_server_listen() 함수 호출에 의해 생성되는 서버측 정보를 가짐
- hal 모듈에서는 서버 구조체를 이용하여 작업
- powersave 모듈은 서버 구조체를 이용하지 않도록 되어 있음
- DBusConnection
- #define DBUS_PATH_DBUS "/org/freedesktop/DBus"
- #define DBUS_SERVICE_DBUS "org.freedesktop.DBus"
- #define DBUS_PATH_LOCAL "/org/freedesktop/DBus/Local"
- enum DBusBusType
- DBUS_BUS_SESSION - The login session bus.
- DBUS_BUS_SYSTEM - The systemwide bus.
- DBUS_BUS_STARTER
- dbus_bus_get() - 시스템 디폴트 값을 이용 (환경 변수 이용) - 이미 알려진 메시지 버스를 자동으로 open 할때 사용함. - connection_try_from_address_entry() - 직접 어드레스 정보를 이용하여 connection을 생성함 - dbus_bus_request_name (DBusConnection *connection, const char *name, unsigned int flags, DBusError *error) - DBUS_SERVICE_DBUS 에서 RequestName method 를 호출하여 name 이 등록되어 있는지 확인하고 등록한다. - dbus_bus_add_match(DBusConnection *connection, const char *rule, DBusError *error) - DBUS_SERVICE_DBUS 에서 AddMatch method 를 호출하여 rule 에 맞는 메시지만을 받을 수 있도록 한다. - dbus_connection_send (DBusConnection *connection, DBusMessage *message, dbus_uint32_t *serial) - 메시지를 전송하고 블럭킹되지 않고 다음 작업을 진행한다. - dbus_connection_send_with_reply (DBusConnection *connection, DBusMessage *message, DBusPendingCall **pending_return, int timeout_milliseconds) - 메시지를 전송후 reply 가 오거나 timeout이 발생할 경우의 동작할 pending을 등록한다. (논블록킹) - dbus_connection_read_write (DBusConnection *connection, int timeout_milliseconds) - 논블로킹 모드로 메시지를 쓰거나 읽는다. - dbus_connection_pop_message (DBusConnection *connection) - 메시지를 하나씩 얻어 온다.
- DBusMessage
- DBUS_MESSAGE_TYPE_INVALID 0
- DBUS_MESSAGE_TYPE_METHOD_CALL 1
- DBUS_MESSAGE_TYPE_METHOD_RETURN 2
- DBUS_MESSAGE_TYPE_ERROR 3
- DBUS_MESSAGE_TYPE_SIGNAL 4
- dbus_message_new_signal (const char *path, const char *interface, const char *name) - 시그널 메시지를 생성한다. - dbus_message_new_method_call(const char *destination, const char *path, const char *interface, const char *method) - 메쏘드 메시지를 생성한다. - dbus_message_new_method_return(DBusMessage *method_call) - DBUS_MESSAGE_TYPE_METHOD_RETURN 타입의 메시지를 생성한다.
- DBusMessageIter
- dbus_message_iter_init_append (DBusMessage *message, DBusMessageIter *iter) - 메시지에 가변 변수가 등록 가능하도록 초기화한다 - dbus_message_iter_append_basic (DBusMessageIter *iter, int type, const void *value) - 메시지에 변수타입과 값을 추가한다.
- DBusError
- error.message 를 변수를 직접 접근하여 에러메시지를 얻을 수 있다.
- dbus_error_init (DBusError *error) - dbus_error_is_set (const DBusError *error) - dbus_error_free(DBusError *error)
- DBusPendingCall
- dbus_pending_call_block(DBusPendingCall *pending) - 콜백함수가 완료 될때까지 블럭킹된다 - dbus_pending_call_steal_reply(DBusPendingCall *pending) - Reply 값을 반환한다.
- DBusAddressEntry
- method : unix, tcp ...
- key : path, tmpdir, abstract ...
- value
Gnome Screen Saver 메시지 예
dbus-monitor 를 실행하여 dbus 메시지를 확인
signal sender=:1.11 -> dest=(null destination) path=/org/gnome/ScreenSaver; interface=org.gnome.ScreenSaver; member=SessionPowerManagementIdleChanged boolean false signal sender=:1.11 -> dest=(null destination) path=/org/gnome/ScreenSaver; interface=org.gnome.ScreenSaver; member=SessionPowerManagementIdleChanged boolean false
'etc' 카테고리의 다른 글
c++ reference site (0) | 2013.11.18 |
---|---|
set up - ubuntu (0) | 2013.11.11 |
dropbox image test (0) | 2013.11.11 |
test (0) | 2013.11.10 |
test (0) | 2013.11.10 |