반응형

 

이 예제를 통해, 다양한 타입(정수(i), 문자열(s), 불리언(b))로 파라미터를 받아 DBus Method call을 처리하고 다양한 타입으로 반환해본다.

 

프로젝트 구조

project/
├── CMakeLists.txt
├── example.xml
├── server.cpp
└── client.cpp

example.xml

<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
 "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
<node>
  <interface name="org.example.Calculator">
    <method name="Add">
      <arg type="i" name="a" direction="in"/>
      <arg type="i" name="b" direction="in"/>
      <arg type="i" name="result" direction="out"/>
    </method>
    <method name="Sub">
      <arg type="i" name="a" direction="in"/>
      <arg type="i" name="b" direction="in"/>
      <arg type="i" name="result" direction="out"/>
    </method>
    <method name="RegisterName">
      <arg type="s" name="inputLastName" direction="in"/>
      <arg type="s" name="inputFirstName" direction="in"/>
      <arg type="s" name="outputFullName" direction="out"/>
    </method>
    <method name="Alert">
    </method>
    <method name="Warning">
      <arg type="s" name="inputLastName" direction="in"/>
    </method>
    <method name="Power">
      <arg type="b" name="mode" direction="in"/>
      <arg type="b" name="status" direction="out"/>
    </method>
    <signal name="CalculationDone">
      <arg type="s" name="operation"/>
      <arg type="i" name="result"/>
    </signal>
  </interface>
</node>

 

 

server.cpp

#include <glib.h>
#include <gio/gio.h>
#include <string>

extern "C" {
    #include "calculator-generated.h"
}

static Calculator *calculator_skeleton = nullptr;
static gboolean power_status = FALSE;

extern "C" {
    static gboolean
    on_handle_add(Calculator *object,
                  GDBusMethodInvocation *invocation,
                  gint a, gint b,
                  gpointer user_data)
    {
        gint result = a + b;
        calculator_complete_add(object, invocation, result);
        
        gchar *msg = g_strdup_printf("Add(%d, %d)", a, b);
        calculator_emit_calculation_done(object, msg, result);
        g_free(msg);
        
        g_print("Add: %d + %d = %d\n", a, b, result);
        return TRUE;
    }

    static gboolean
    on_handle_sub(Calculator *object,
                  GDBusMethodInvocation *invocation,
                  gint a, gint b,
                  gpointer user_data)
    {
        gint result = a - b;
        calculator_complete_sub(object, invocation, result);
        
        gchar *msg = g_strdup_printf("Sub(%d, %d)", a, b);
        calculator_emit_calculation_done(object, msg, result);
        g_free(msg);
        
        g_print("Sub: %d - %d = %d\n", a, b, result);
        return TRUE;
    }

    static gboolean
    on_handle_register_name(Calculator *object,
                           GDBusMethodInvocation *invocation,
                           const gchar *last_name,
                           const gchar *first_name,
                           gpointer user_data)
    {
        gchar *full_name = g_strdup_printf("%s %s", first_name, last_name);
        calculator_complete_register_name(object, invocation, full_name);
        
        g_print("RegisterName: %s + %s = %s\n", first_name, last_name, full_name);
        g_free(full_name);
        
        return TRUE;
    }

    static gboolean
    on_handle_alert(Calculator *object,
                   GDBusMethodInvocation *invocation,
                   gpointer user_data)
    {
        g_print("Alert: No arguments received\n");
        calculator_complete_alert(object, invocation);
        return TRUE;
    }

    static gboolean
    on_handle_warning(Calculator *object,
                     GDBusMethodInvocation *invocation,
                     const gchar *last_name,
                     gpointer user_data)
    {
        g_print("Warning: Received last name = %s\n", last_name);
        calculator_complete_warning(object, invocation);
        return TRUE;
    }

    static gboolean
    on_handle_power(Calculator *object,
                   GDBusMethodInvocation *invocation,
                   gboolean mode,
                   gpointer user_data)
    {
        power_status = mode;
        g_print("Power: Mode set to %s\n", mode ? "ON" : "OFF");
        calculator_complete_power(object, invocation, power_status);
        return TRUE;
    }

    static void
    on_bus_acquired(GDBusConnection *connection,
                    const gchar *name,
                    gpointer user_data)
    {
        GError *error = nullptr;
        
        calculator_skeleton = calculator_skeleton_new();
        
        g_signal_connect(calculator_skeleton, "handle-add",
                         G_CALLBACK(on_handle_add), nullptr);
        g_signal_connect(calculator_skeleton, "handle-sub",
                         G_CALLBACK(on_handle_sub), nullptr);
        g_signal_connect(calculator_skeleton, "handle-register-name",
                         G_CALLBACK(on_handle_register_name), nullptr);
        g_signal_connect(calculator_skeleton, "handle-alert",
                         G_CALLBACK(on_handle_alert), nullptr);
        g_signal_connect(calculator_skeleton, "handle-warning",
                         G_CALLBACK(on_handle_warning), nullptr);
        g_signal_connect(calculator_skeleton, "handle-power",
                         G_CALLBACK(on_handle_power), nullptr);
        
        if (!g_dbus_interface_skeleton_export(
                G_DBUS_INTERFACE_SKELETON(calculator_skeleton),
                connection,
                "/org/example/Calculator",
                &error))
        {
            g_printerr("Failed to export object: %s\n", error->message);
            g_error_free(error);
        }
        else
        {
            g_print("Calculator service ready\n");
        }
    }

    static void
    on_name_acquired(GDBusConnection *connection,
                     const gchar *name,
                     gpointer user_data)
    {
        g_print("Name acquired: %s\n", name);
    }

    static void
    on_name_lost(GDBusConnection *connection,
                 const gchar *name,
                 gpointer user_data)
    {
        g_printerr("Name lost: %s\n", name);
    }
}

int main(void)
{
    GMainLoop *loop;
    guint owner_id;
    
    loop = g_main_loop_new(nullptr, FALSE);
    
    owner_id = g_bus_own_name(G_BUS_TYPE_SESSION,
                               "org.example.Calculator",
                               G_BUS_NAME_OWNER_FLAGS_NONE,
                               on_bus_acquired,
                               on_name_acquired,
                               on_name_lost,
                               nullptr, nullptr);
    
    g_main_loop_run(loop);
    
    g_bus_unown_name(owner_id);
    g_main_loop_unref(loop);
    if (calculator_skeleton)
        g_object_unref(calculator_skeleton);
    
    return 0;
}

 

client.cpp

#include <glib.h>
#include <gio/gio.h>

extern "C" {
    #include "calculator-generated.h"
}

extern "C" {
    static void
    on_calculation_done(Calculator *proxy,
                        const gchar *operation,
                        gint result,
                        gpointer user_data)
    {
        g_print("Signal received: %s = %d\n", operation, result);
    }
}

int main(void)
{
    GError *error = nullptr;
    Calculator *proxy;
    gint result;
    gchar *full_name = nullptr;
    gboolean power_status;
    
    proxy = calculator_proxy_new_for_bus_sync(
        G_BUS_TYPE_SESSION,
        G_DBUS_PROXY_FLAGS_NONE,
        "org.example.Calculator",
        "/org/example/Calculator",
        nullptr, &error);
    
    if (error)
    {
        g_printerr("Failed to create proxy: %s\n", error->message);
        g_error_free(error);
        return 1;
    }
    
    // Signal 연결
    g_signal_connect(proxy, "calculation-done",
                     G_CALLBACK(on_calculation_done), nullptr);
    
    // 1. Add 호출
    g_print("\n=== Testing Add ===\n");
    if (calculator_call_add_sync(proxy, 10, 5, &result, nullptr, &error))
    {
        g_print("Add result: %d\n", result);
    }
    else
    {
        g_printerr("Add failed: %s\n", error->message);
        g_clear_error(&error);
    }
    
    // 2. Sub 호출
    g_print("\n=== Testing Sub ===\n");
    if (calculator_call_sub_sync(proxy, 10, 5, &result, nullptr, &error))
    {
        g_print("Sub result: %d\n", result);
    }
    else
    {
        g_printerr("Sub failed: %s\n", error->message);
        g_clear_error(&error);
    }
    
    // 3. RegisterName 호출
    g_print("\n=== Testing RegisterName ===\n");
    if (calculator_call_register_name_sync(proxy, "Kim", "Chulsoo", 
                                          &full_name, nullptr, &error))
    {
        g_print("RegisterName result: %s\n", full_name);
        g_free(full_name);
    }
    else
    {
        g_printerr("RegisterName failed: %s\n", error->message);
        g_clear_error(&error);
    }
    
    // 4. Alert 호출 (인자 없음)
    g_print("\n=== Testing Alert ===\n");
    if (calculator_call_alert_sync(proxy, nullptr, &error))
    {
        g_print("Alert: Success (no return value)\n");
    }
    else
    {
        g_printerr("Alert failed: %s\n", error->message);
        g_clear_error(&error);
    }
    
    // 5. Warning 호출 (입력만 있고 출력 없음)
    g_print("\n=== Testing Warning ===\n");
    if (calculator_call_warning_sync(proxy, "Park", nullptr, &error))
    {
        g_print("Warning: Success (no return value)\n");
    }
    else
    {
        g_printerr("Warning failed: %s\n", error->message);
        g_clear_error(&error);
    }
    
    // 6. Power 호출 (boolean 타입)
    g_print("\n=== Testing Power ===\n");
    if (calculator_call_power_sync(proxy, TRUE, &power_status, nullptr, &error))
    {
        g_print("Power result: %s\n", power_status ? "ON" : "OFF");
    }
    else
    {
        g_printerr("Power failed: %s\n", error->message);
        g_clear_error(&error);
    }
    
    // Signal 수신 대기
    g_print("\n=== Waiting for signals (Press Ctrl+C to exit) ===\n");
    GMainLoop *loop = g_main_loop_new(nullptr, FALSE);
    g_main_loop_run(loop);
    
    g_object_unref(proxy);
    g_main_loop_unref(loop);
    
    return 0;
}

 

 

빌드

mkdir build && cd build
cmake ..
make

 

실행방법

서버측:

./calculator_server

 

클라이언트측:

./calculator_client

 

실행결과

서버측:

Calculator service ready
Name acquired: org.example.Calculator
Add: 10 + 5 = 15
Sub: 10 - 5 = 5
RegisterName: Chulsoo + Kim = Chulsoo Kim
Alert: No arguments received
Warning: Received last name = Park
Power: Mode set to ON

 

클라이언트측:

=== Testing Add ===
Add result: 15

=== Testing Sub ===
Sub result: 5

=== Testing RegisterName ===
RegisterName result: Chulsoo Kim

=== Testing Alert ===
Alert: Success (no return value)

=== Testing Warning ===
Warning: Success (no return value)

=== Testing Power ===
Power result: ON

=== Waiting for signals (Press Ctrl+C to exit) ===
Signal received: Add(10, 5) = 15
Signal received: Sub(10, 5) = 5

 

반응형