Linux에서 dbus-c++바인딩으로 서비스를 제공하는 프로세스 구현 방법을 소개한다.
참고로 dbus-c++ 바인더는 2011년 이후로 개발이 중지된 상태이지만 여기선 간단히 개념을 설명하기 위해 사용하였다. 현재 C++위한 바인더로 dbus-cxx, dbus-cpp, Qt D-Bus, GDBus 등이 있다.
먼저 아래명령으로 c++바인딩 패키지를 설치한다.
apt-get install libdbus-c++-bin libdbus-c++-dev
작업 폴더를 만들고 아래의 예제처럼 xml로 인터페이스를 작성한다.
아래의 예제에서 type="s" name="name" direction="in" 이것은 string타입의 입력 인자를 의미한다.
interface.xml
<?xml version="1.0" ?>
<node name="/org/freedesktop/DBus/Examples/Echo">
<interface name="org.freedesktop.DBus.EchoDemo">
<method name="HelloString">
<arg type="s" name="name" direction="in"/>
<arg type="s" name="greeting" direction="out"/>
</method>
<signal name="EchoCount">
<arg type="y" name="count"/>
</signal>
</interface>
</node>
아래표는 D-Bus에서 사용하는 타입들이다.
|
Category |
Conventional Name |
Code |
Description |
|
reserved |
INVALID |
0 (ASCII NUL) |
Not a valid type code, used to terminate signatures |
|
fixed, basic |
BYTE |
121 (ASCII 'y') |
8-bit unsigned integer |
|
fixed, basic |
BOOLEAN |
98 (ASCII 'b') |
Boolean value, 0 is FALSE and 1 is TRUE. Everything else is invalid. |
|
fixed, basic |
INT16 |
110 (ASCII 'n') |
16-bit signed integer |
|
fixed, basic |
UINT16 |
113 (ASCII 'q') |
16-bit unsigned integer |
|
fixed, basic |
INT32 |
105 (ASCII 'i') |
32-bit signed integer |
|
fixed, basic |
UINT32 |
117 (ASCII 'u') |
32-bit unsigned integer |
|
fixed, basic |
INT64 |
120 (ASCII 'x') |
64-bit signed integer |
|
fixed, basic |
UINT64 |
116 (ASCII 't') |
64-bit unsigned integer |
|
fixed, basic |
DOUBLE |
100 (ASCII 'd') |
IEEE 754 double |
|
string-like, basic |
STRING |
115 (ASCII 's') |
UTF-8 string (must be valid UTF-8). Must be nul terminated and contain no other nul bytes. |
|
string-like, basic |
OBJECT_PATH |
111 (ASCII 'o') |
Name of an object instance |
|
string-like, basic |
SIGNATURE |
103 (ASCII 'g') |
A type signature |
|
container |
ARRAY |
97 (ASCII 'a') |
Array |
|
container |
STRUCT |
114 (ASCII 'r'), 40 (ASCII '('), 41 (ASCII ')') |
Struct; type code 114 'r' is reserved for use in bindings and implementations to represent the general concept of a struct, and must not appear in signatures used on D-Bus. |
|
container |
VARIANT |
118 (ASCII 'v') |
Variant type (the type of the value is part of the value itself) |
|
container |
DICT_ENTRY |
101 (ASCII 'e'), 123 (ASCII '{'), 125 (ASCII '}') |
Entry in a dict or map (array of key-value pairs). Type code 101 'e' is reserved for use in bindings and implementations to represent the general concept of a dict or dict-entry, and must not appear in signatures used on D-Bus. |
|
fixed, basic |
UNIX_FD |
104 (ASCII 'h') |
Unix file descriptor |
|
reserved |
(reserved) |
109 (ASCII 'm') |
Reserved for a 'maybe' type compatible with the one in GVariant, and must not appear in signatures used on D-Bus until specified here |
|
reserved |
(reserved) |
42 (ASCII '*') |
Reserved for use in bindings/implementations to represent any single complete type, and must not appear in signatures used on D-Bus. |
|
reserved |
(reserved) |
63 (ASCII '?') |
Reserved for use in bindings/implementations to represent any basic type, and must not appear in signatures used on D-Bus. |
|
reserved |
(reserved) |
64 (ASCII '@'), 38 (ASCII '&'), 94 (ASCII '^') |
Reserved for internal use by bindings/implementations, and must not appear in signatures used on D-Bus. GVariant uses these type-codes to encode calling conventions. |
작성된 xml을 service를 제공하는 쪽에서 사용 할 헤더파일로 변환한다.
dbusxx-xml2cpp interface.xml --adaptor=echo-interface-adaptor.h
변환된 헤더파일은 대략 아래와 같다.
echo-interface-adaptor.h
/*
* This file was automatically generated by dbusxx-xml2cpp; DO NOT EDIT!
*/
#ifndef __dbusxx__echo_interface_adaptor_h__ADAPTOR_MARSHAL_H
#define __dbusxx__echo_interface_adaptor_h__ADAPTOR_MARSHAL_H
#include <dbus-c++/dbus.h>
#include <cassert>
namespace org {
namespace freedesktop {
namespace DBus {
class EchoDemo_adaptor
: public ::DBus::InterfaceAdaptor
{
public:
EchoDemo_adaptor()
: ::DBus::InterfaceAdaptor("org.freedesktop.DBus.EchoDemo")
{
register_method(EchoDemo_adaptor, HelloString, _HelloString_stub);
}
::DBus::IntrospectedInterface *introspect() const
{
static ::DBus::IntrospectedArgument HelloString_args[] =
{
{ "name", "s", true },
{ "greeting", "s", false },
{ 0, 0, 0 }
};
static ::DBus::IntrospectedArgument EchoCount_args[] =
{
{ "count", "y", false },
{ 0, 0, 0 }
};
static ::DBus::IntrospectedMethod EchoDemo_adaptor_methods[] =
{
{ "HelloString", HelloString_args },
{ 0, 0 }
};
static ::DBus::IntrospectedMethod EchoDemo_adaptor_signals[] =
{
{ "EchoCount", EchoCount_args },
{ 0, 0 }
};
static ::DBus::IntrospectedProperty EchoDemo_adaptor_properties[] =
{
{ 0, 0, 0, 0 }
};
static ::DBus::IntrospectedInterface EchoDemo_adaptor_interface =
{
"org.freedesktop.DBus.EchoDemo",
EchoDemo_adaptor_methods,
EchoDemo_adaptor_signals,
EchoDemo_adaptor_properties
};
return &EchoDemo_adaptor_interface;
}
public:
/* properties exposed by this interface, use
* property() and property(value) to get and set a particular property
*/
public:
/* methods exported by this interface,
* you will have to implement them in your ObjectAdaptor
*/
virtual std::string HelloString(const std::string& name) = 0;
public:
/* signal emitters for this interface
*/
void EchoCount(const uint8_t& arg1)
{
::DBus::SignalMessage sig("EchoCount");
::DBus::MessageIter wi = sig.writer();
wi << arg1;
emit_signal(sig);
}
private:
/* unmarshalers (to unpack the DBus message before calling the actual interface method)
*/
::DBus::Message _HelloString_stub(const ::DBus::CallMessage &call)
{
::DBus::MessageIter ri = call.reader();
std::string argin1; ri >> argin1;
std::string argout1 = HelloString(argin1);
::DBus::ReturnMessage reply(call);
::DBus::MessageIter wi = reply.writer();
wi << argout1;
return reply;
}
};
} } }
#endif //__dbusxx__echo_interface_adaptor_h__ADAPTOR_MARSHAL_H
이제 위의 클래스를 상속받고 가상함수를 오버라이드하여 정의한다.
echo-server.h
#include "echo-interface-adaptor.h"
class EchoServer : public org::freedesktop::DBus::EchoDemo_adaptor,
public DBus::IntrospectableAdaptor,
public DBus::ObjectAdaptor
{
public:
EchoServer(DBus::Connection * conn);
virtual ~EchoServer();
public:
virtual std::string HelloString(const std::string& name);
};
echo-server.cpp
#include "echo-server.h"
#include <stdio.h>
EchoServer::EchoServer(DBus::Connection * conn)
: DBus::ObjectAdaptor(*conn, "/org/freedesktop/DBus/Examples/Echo")
{
}
EchoServer::~EchoServer()
{
}
std::string EchoServer::HelloString(const std::string& name)
{
printf("Input string : %s\n", name.c_str() );
std::string ret = name + " world!!";
return ret;
}
main함수에서는 service를 위한 SessionBus 연결 및 객체를 생성한다.
main.cpp
#include "echo-server.h"
#include <unistd.h>
#include <future>
#include <stdio.h>
DBus::BusDispatcher dispatcher;
int main()
{
DBus::default_dispatcher = &dispatcher;
DBus::_init_threading();
DBus::Connection conn = DBus::Connection::SessionBus();
conn.request_name("org.freedesktop.DBus.EchoService");
EchoServer server(&conn);
uint8_t count = 0;
std::future<void>fut = std::async(std::launch::async, [=] {
dispatcher.enter();
});
// emit EchoSignal every seconds.
while ( true )
{
printf("emit signal 'EchoSignal' count : %d\n", count);
server.EchoCount(count++);
sleep(1);
}
return 0;
}
dbus-c++-1 라이브러리 및 INCLUDE Path를 컴파일 시에 인자로 넘겨준다.
이제 구현 테스트를 위한 방법으로 우분투 소프트웨어 센터에서 "D-Feet" 검색하고 설치한다.
어플리케이션을 실행한 상태에서 D-Feet을 실행하고 Session Bus 탭을 선택 후 "echo"를 검색하면 아래처럼 보일 것이다.

오른쪽 Object path영역에서 인터페이스를 펼치면 아래처럼 서비스쪽의 Methods 및 Signals 등이 보인다.
Methods에서 HelloString을 더블클릭한다.

Input영역에 문자열 입력 후 Execute를 클릭한다.

그러면 service 쪽 출력내용이 다음과 같이 보일 것이다.

이 서비스 프로세스와 통신하는 클라이언트는 파이썬으로 구현, 테스트 예제: https://makersweb.net/python/6517
윈도우에서 Qt D-Bus를 사용한 예제: https://makersweb.net/qt/13174
| 번호 | 제목 | 글쓴이 | 날짜 | 조회 수 |
|---|---|---|---|---|
| 25 | libblkid - USB Storage의 정보 가져오기 | makersweb | 2018.10.18 | 2826 |
| 24 | tslib 크로스 컴파일과 터치스크린 보정 | makersweb | 2018.08.02 | 4751 |
| » |
Ubuntu Linux에서 dbus-c++바인딩 D-Bus 테스트
| makersweb | 2018.03.07 | 10091 |
| 22 | NFS를 통해 파일시스템 공유 | makersweb | 2018.03.05 | 3114 |
| 21 |
Wayland에 대한 간단한 소개
| makersweb | 2017.12.29 | 5813 |
| 20 |
Ubuntu16.04에서 weston구동
| makersweb | 2017.12.28 | 3731 |
| 19 | UVC 장치를 사용할때 v4l2: select timeout 에러 발생 | makersweb | 2017.12.27 | 5108 |
| 18 |
[IPC]D-Bus 소개
| makersweb | 2015.02.28 | 32423 |
| 17 | 리눅스 데스크탑 환경 종류 | pjk | 2015.02.11 | 6894 |
| 16 | 디바이스 드라이버에 대해서 | makersweb | 2014.04.19 | 6968 |
| 15 |
리눅스 커널 소스코드 구성도
| makersweb | 2014.03.04 | 8074 |
| 14 | read() 함수, write() 함수 | makersweb | 2014.03.04 | 14353 |
| 13 | 리눅스 디렉터리 구조 | makersweb | 2014.02.28 | 5266 |
| 12 | 1. make | pjk | 2014.02.05 | 4324 |
| 11 | 2. 간단한 Makefile | pjk | 2014.02.05 | 5120 |
| 10 | 3. 매크로(Macro) 와 확장자(Suffix) 규칙 | pjk | 2014.02.05 | 4724 |
| 9 | 4. Makefile를 작성할 때 알면 좋은 것들 | pjk | 2014.02.05 | 6184 |
| 8 | 5. make 중요 옵션 정리 | pjk | 2014.02.05 | 5092 |
| 7 | 6. Makefile 작성의 가이드라인 | pjk | 2014.02.05 | 4151 |
| 6 | mmap() 함수, munmap() 함수 | pjk | 2014.02.05 | 18745 |