D-BUS
[D-BUS] client.c server.c 예제
2025. 3. 26. 00:06반응형
GLib을 사용한 GDBus 예제 (Client/Server 구조)
다음은 GLib의 GDBus를 사용한 간단한 클라이언트-서버 예제입니다. 이 예제에서는 서버가 계산기 서비스를 제공하고 클라이언트가 그 서비스를 사용합니다.
서버 코드 (server.c)
#include <glib.h>
#include <gio/gio.h>
/* 인터페이스 XML 정의 */
static const gchar *interface_xml =
"<node>"
" <interface name='org.example.Calculator'>"
" <method name='Add'>"
" <arg type='d' name='a' direction='in'/>"
" <arg type='d' name='b' direction='in'/>"
" <arg type='d' name='result' direction='out'/>"
" </method>"
" <method name='Subtract'>"
" <arg type='d' name='a' direction='in'/>"
" <arg type='d' name='b' direction='in'/>"
" <arg type='d' name='result' direction='out'/>"
" </method>"
" <signal name='CalculationDone'>"
" <arg type='d' name='result'/>"
" </signal>"
" <property name='LastResult' type='d' access='read'/>"
" </interface>"
"</node>";
static GDBusNodeInfo *introspection_data = NULL;
static gdouble last_result = 0.0;
/* 메소드 호출 처리 */
static void handle_method_call(GDBusConnection *connection,
const gchar *sender,
const gchar *object_path,
const gchar *interface_name,
const gchar *method_name,
GVariant *parameters,
GDBusMethodInvocation *invocation,
gpointer user_data)
{
if (g_strcmp0(interface_name, "org.example.Calculator") == 0)
{
if (g_strcmp0(method_name, "Add") == 0)
{
gdouble a, b;
g_variant_get(parameters, "(dd)", &a, &b);
last_result = a + b;
// 결과 반환
g_dbus_method_invocation_return_value(invocation,
g_variant_new("(d)", last_result));
// 시그널 발송
g_dbus_connection_emit_signal(connection,
NULL,
object_path,
"org.example.Calculator",
"CalculationDone",
g_variant_new("(d)", last_result),
NULL);
}
else if (g_strcmp0(method_name, "Subtract") == 0)
{
gdouble a, b;
g_variant_get(parameters, "(dd)", &a, &b);
last_result = a - b;
g_dbus_method_invocation_return_value(invocation,
g_variant_new("(d)", last_result));
g_dbus_connection_emit_signal(connection,
NULL,
object_path,
"org.example.Calculator",
"CalculationDone",
g_variant_new("(d)", last_result),
NULL);
}
}
}
/* 프로퍼티 가져오기 처리 */
static GVariant *handle_get_property(GDBusConnection *connection,
const gchar *sender,
const gchar *object_path,
const gchar *interface_name,
const gchar *property_name,
GError **error,
gpointer user_data)
{
if (g_strcmp0(interface_name, "org.example.Calculator") == 0)
{
if (g_strcmp0(property_name, "LastResult") == 0)
{
return g_variant_new_double(last_result);
}
}
g_set_error(error, G_IO_ERROR, G_IO_ERROR_FAILED, "Unknown property");
return NULL;
}
int main(int argc, char *argv[])
{
GMainLoop *loop;
GDBusConnection *connection;
GError *error = NULL;
guint owner_id;
g_type_init();
loop = g_main_loop_new(NULL, FALSE);
// 인트로스펙션 데이터 생성
introspection_data = g_dbus_node_info_new_for_xml(interface_xml, NULL);
// D-Bus에 서비스 등록
owner_id = g_bus_own_name(G_BUS_TYPE_SESSION,
"org.example.CalculatorService",
G_BUS_NAME_OWNER_FLAGS_NONE,
NULL, /* on_bus_name_acquired */
NULL, /* on_name_acquired */
NULL, /* on_name_lost */
NULL, /* user_data */
NULL); /* user_data_free_func */
connection = g_bus_get_sync(G_BUS_TYPE_SESSION, NULL, &error);
if (connection == NULL)
{
g_printerr("Failed to connect to D-Bus: %s\n", error->message);
g_error_free(error);
return 1;
}
// 객체 매니저 등록
GDBusInterfaceVTable interface_vtable = {
handle_method_call,
handle_get_property,
NULL /* set_property */
};
guint registration_id = g_dbus_connection_register_object(connection,
"/org/example/Calculator",
introspection_data->interfaces[0],
&interface_vtable,
NULL, /* user_data */
NULL, /* user_data_free_func */
&error);
if (registration_id == 0)
{
g_printerr("Failed to register object: %s\n", error->message);
g_error_free(error);
return 1;
}
g_print("Calculator service is running...\n");
g_main_loop_run(loop);
// 정리
g_dbus_connection_unregister_object(connection, registration_id);
g_bus_unown_name(owner_id);
g_object_unref(connection);
g_main_loop_unref(loop);
g_dbus_node_info_unref(introspection_data);
return 0;
}
클라이언트 코드 (client.c)
#include <glib.h>
#include <gio/gio.h>
static GMainLoop *loop;
/* 시그널 핸들러 */
static void on_calculation_done(GDBusConnection *connection,
const gchar *sender_name,
const gchar *object_path,
const gchar *interface_name,
const gchar *signal_name,
GVariant *parameters,
gpointer user_data)
{
gdouble result;
g_variant_get(parameters, "(d)", &result);
g_print("Received CalculationDone signal: Result is %g\n", result);
}
/* 비동기 호출 완료 콜백 */
static void on_call_finished(GObject *source_object,
GAsyncResult *res,
gpointer user_data)
{
GDBusConnection *connection = G_DBUS_CONNECTION(source_object);
GVariant *result;
GError *error = NULL;
result = g_dbus_connection_call_finish(connection, res, &error);
if (error != NULL)
{
g_printerr("Error calling method: %s\n", error->message);
g_error_free(error);
g_main_loop_quit(loop);
return;
}
gdouble out;
g_variant_get(result, "(d)", &out);
g_print("Method call result: %g\n", out);
g_variant_unref(result);
// 프로퍼티 읽기
GVariant *property_value = g_dbus_connection_call_sync(connection,
"org.example.CalculatorService",
"/org/example/Calculator",
"org.freedesktop.DBus.Properties",
"Get",
g_variant_new("(ss)",
"org.example.Calculator",
"LastResult"),
NULL,
G_DBUS_CALL_FLAGS_NONE,
-1,
NULL,
&error);
if (property_value == NULL)
{
g_printerr("Error getting property: %s\n", error->message);
g_error_free(error);
}
else
{
GVariant *value;
g_variant_get(property_value, "(v)", &value);
g_print("LastResult property: %g\n", g_variant_get_double(value));
g_variant_unref(value);
g_variant_unref(property_value);
}
g_main_loop_quit(loop);
}
int main(int argc, char *argv[])
{
GDBusConnection *connection;
GError *error = NULL;
guint signal_subscription_id;
g_type_init();
loop = g_main_loop_new(NULL, FALSE);
connection = g_bus_get_sync(G_BUS_TYPE_SESSION, NULL, &error);
if (connection == NULL)
{
g_printerr("Failed to connect to D-Bus: %s\n", error->message);
g_error_free(error);
return 1;
}
// 시그널 구독
signal_subscription_id = g_dbus_connection_signal_subscribe(connection,
"org.example.CalculatorService",
"org.example.Calculator",
"CalculationDone",
"/org/example/Calculator",
NULL,
G_DBUS_SIGNAL_FLAGS_NONE,
on_calculation_done,
NULL,
NULL);
// 비동기 메소드 호출
g_dbus_connection_call(connection,
"org.example.CalculatorService",
"/org/example/Calculator",
"org.example.Calculator",
"Add",
g_variant_new("(dd)", 10.5, 20.3),
NULL,
G_DBUS_CALL_FLAGS_NONE,
-1,
NULL,
on_call_finished,
NULL);
g_print("Waiting for method call to complete...\n");
g_main_loop_run(loop);
// 정리
g_dbus_connection_signal_unsubscribe(connection, signal_subscription_id);
g_object_unref(connection);
g_main_loop_unref(loop);
return 0;
}
컴파일 및 실행 방법
- 필요한 패키지 설치 (Ubuntu 기준):
sudo apt-get install libglib2.0-dev libgio2.0-dev
- 컴파일:
gcc -o server server.c `pkg-config --cflags --libs gio-2.0`
gcc -o client client.c `pkg-config --cflags --libs gio-2.0`
- 실행:
- 먼저 서버를 실행합니다:
./server
- 다른 터미널에서 클라이언트를 실행합니다:
./client
예제 설명
- 서버:
- org.example.Calculator 인터페이스를 정의하고 D-Bus에 등록
- Add와 Subtract 메소드 제공
- CalculationDone 시그널과 LastResult 프로퍼티 제공
- 세션 버스를 통해 org.example.CalculatorService 이름으로 서비스 제공
- 클라이언트:
- 서버의 Add 메소드를 비동기적으로 호출
- CalculationDone 시그널을 구독하여 결과 알림 수신
- 호출 완료 후 LastResult 프로퍼티 조회
이 예제는 GLib의 GDBus API를 사용하여 D-Bus 서비스와 클라이언트를 구현하는 기본적인 방법을 보여줍니다. 실제 애플리케이션에서는 더 많은 오류 처리와 복잡한 기능이 필요할 수 있습니다.
반응형
'D-BUS' 카테고리의 다른 글
(비) [D-BUS] 간단한 예제 CMakefile.txt 작성법 - bb file 작성법 (0) | 2025.03.28 |
---|---|
[D-BUS] D-BUS란? (0) | 2025.03.24 |