반응형
dbus-send --session --dest=org.example.CalculatorService --type=method_call \
	--print-reply \
    /org/example/Calculator \
    org.example.Calculator.Sub \
    double:5.0 double:2.0

소스코드

파일 : dbus_method_receiver.c

#include <stdio.h>
#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='Sub'>"
  "      <arg type='d' name='a' direction='in'/>"
  "      <arg type='d' name='b' direction='in'/>"
  "      <arg type='d' name='result' direction='out'/>"
  "    </method>"
  "  </interface>"
  "</node>";
  
guint registration_id = 0;

static GDBusNodeInfo *introspection_data = NULL;

/* 메소드 호출 처리 */
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)
{
  // 디버깅 정보 출력
  gchar *parameters_str = g_variant_print(parameters, TRUE);
  printf("Sender: %s\n", sender);
  printf("Object Path: %s\n", object_path);
  printf("Interface: %s\n", interface_name);
  printf("method_name: %s\n", method_name);
  printf("Parameters: %s\n", parameters_str);
  g_free(parameters_str);

  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);
      double result = a + b;
      
      // 결과 반환
      g_dbus_method_invocation_return_value(invocation, 
                                           g_variant_new("(d)", result));
    }
    else if (g_strcmp0(method_name, "Sub") == 0)
    {
      gdouble a, b;
      g_variant_get(parameters, "(dd)", &a, &b);
      double result = a - b;
	  
	  // 결과 반환
      g_dbus_method_invocation_return_value(invocation, 
                                          g_variant_new("(d)", result));
    }
  }
}

// 버스 이름 획득시 호출
static void on_bus_acquired(GDBusConnection *connection,
                            const gchar *name,
                            gpointer user_data)
{
  GError *error = NULL;
	
  // 인터페이스 vtable 정의. vtable은 D-Bus 인터페이스의 동작을 정의하는 콜백함수 테이블로
  // 클라이언트 요청을 처리할 수 있도록 인터페이스의 동작을 구성하는데 사용
  GDBusInterfaceVTable interface_vtable = {
    handle_method_call,  // D-Bus methods(request)를 처리할 때
    NULL, /* get_property, */ // D-Bus 속성을 읽을 때
    NULL /* set_property */ // D-Bus 속성을 설정할 때
  };

  // 객체 등록.
  // D-Bus method(requeest) 처리를 하기위해 vtable을
  // D-Bus 연결에 특정 객체 경로와 인터페이스를 등록하는 함수
  // 이 함수가 호출 되어야, 특정 객체 경로로 부터 받은 D-Bus method(reqeust) 요청을 처리할 수 있다.
  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;
  }
}

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,
                           on_bus_acquired, /* on_bus_acquired */
                           NULL, /* on_name_acquired */
                           NULL, /* on_name_lost */
                           NULL, /* user_data */
                           NULL); /* user_data_free_func */

  // 세션 D-BUS 연결
  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;
  }
  
  g_print("Calculator service is running...\n");

  // 메인 루프 실행
  g_main_loop_run(loop);
  
  // 종료 후 clean-up (리소스 정리)
  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;
}

 

컴파일 방법

gcc -o dbus_method_receiver dbus_method_receiver.c `pkg-config --cflags --libs gio-2.0`

 

 

dbus-send 명령어 (Add)

dbus-send --session --dest=org.example.CalculatorService \
	--type=method_call \
	--print-reply \
	/org/example/Calculator \
	org.example.Calculator.Add \
	double:3.5 double:2.5

 

실행 결과

method return time=1639623456.789012 sender=:1.123 -> destination=:1.124 serial=456 reply_serial=2
   double 6

 

dbus-send 명령어 (Sub)

dbus-send --session --dest=org.example.CalculatorService \
	--type=method_call \
	--print-reply \
	/org/example/Calculator \
	org.example.Calculator.Sub \
	double:5.0 double:2.0

실행 결과

method return time=1639623456.789012 sender=:1.123 -> destination=:1.124 serial=457 reply_serial=2
   double 3

 

 

dbus-send sender 코드

- 파일: dbus_method_sedner.c

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

int main(int argc, char *argv[])
{
    GDBusConnection *connection;
    GError *error = NULL;
    GVariant *result;
    
    // GLib 타입 시스템 초기화
    g_type_init();
    
    // 세션 버스에 연결
    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;
    }
    
    // Add 메서드 호출
    printf("Calling Add(3.5, 2.5)...\n");
    result = g_dbus_connection_call_sync(
        connection,
        "org.example.CalculatorService", // 서비스 이름
        "/org/example/Calculator",       // 객체 경로
        "org.example.Calculator",        // 인터페이스 이름
        "Add",                          // 메서드 이름
        g_variant_new("(dd)", 3.5, 2.5), // 입력 인자 (두 개의 double)
        G_VARIANT_TYPE("(d)"),          // 예상 반환 타입 (double)
        G_DBUS_CALL_FLAGS_NONE,
        -1,                             // 타임아웃 (기본값)
        NULL,                           // GCancellable
        &error
    );
    
    if (result == NULL) {
        g_printerr("Error calling Add: %s\n", error->message);
        g_error_free(error);
    } else {
        gdouble add_result;
        g_variant_get(result, "(d)", &add_result);
        printf("Add result: %f\n", add_result);
        g_variant_unref(result);
    }
    
    // Sub 메서드 호출
    printf("Calling Sub(5.0, 2.0)...\n");
    result = g_dbus_connection_call_sync(
        connection,
        "org.example.CalculatorService",
        "/org/example/Calculator",
        "org.example.Calculator",
        "Sub",
        g_variant_new("(dd)", 5.0, 2.0),
        G_VARIANT_TYPE("(d)"),
        G_DBUS_CALL_FLAGS_NONE,
        -1,
        NULL,
        &error
    );
    
    if (result == NULL) {
        g_printerr("Error calling Sub: %s\n", error->message);
        g_error_free(error);
    } else {
        gdouble sub_result;
        g_variant_get(result, "(d)", &sub_result);
        printf("Sub result: %f\n", sub_result);
        g_variant_unref(result);
    }
    
    // 리소스 정리
    g_object_unref(connection);
    
    return 0;
}

 

 

dbus-send sender 코드 (비동기)

- 파일: dbus_method_sender_async.c

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

// Add 메서드 호출 콜백
static void add_callback(GDBusConnection *connection,
                         GAsyncResult *res,
                         gpointer user_data)
{
    GError *error = NULL;
    GVariant *result = g_dbus_connection_call_finish(connection, res, &error);
    
    if (result == NULL) {
        g_printerr("Error calling Add: %s\n", error->message);
        g_error_free(error);
    } else {
        gdouble add_result;
        g_variant_get(result, "(d)", &add_result);
        printf("Add result: %f\n", add_result);
        g_variant_unref(result);
    }
    
    // 메인 루프 종료 (첫 번째 호출 완료 후)
    g_main_loop_quit((GMainLoop *)user_data);
}

// Sub 메서드 호출 콜백
static void sub_callback(GDBusConnection *connection,
                         GAsyncResult *res,
                         gpointer user_data)
{
    GError *error = NULL;
    GVariant *result = g_dbus_connection_call_finish(connection, res, &error);
    
    if (result == NULL) {
        g_printerr("Error calling Sub: %s\n", error->message);
        g_error_free(error);
    } else {
        gdouble sub_result;
        g_variant_get(result, "(d)", &sub_result);
        printf("Sub result: %f\n", sub_result);
        g_variant_unref(result);
    }
    
    // 두 번째 호출 완료 후
    g_main_loop_quit((GMainLoop *)user_data);
}

int main(int argc, char *argv[])
{
    GDBusConnection *connection;
    GError *error = NULL;
    GMainLoop *loop;
    
    // GLib 타입 시스템 초기화
    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;
    }
    
    // Add 메서드 비동기 호출
    printf("Calling Add(3.5, 2.5) asynchronously...\n");
    g_dbus_connection_call(
        connection,
        "org.example.CalculatorService", // 서비스 이름
        "/org/example/Calculator",       // 객체 경로
        "org.example.Calculator",        // 인터페이스 이름
        "Add",                          // 메서드 이름
        g_variant_new("(dd)", 3.5, 2.5), // 입력 인자 (두 개의 double)
        G_VARIANT_TYPE("(d)"),          // 예상 반환 타입 (double)
        G_DBUS_CALL_FLAGS_NONE,
        -1,                             // 타임아웃 (기본값)
        NULL,                           // GCancellable
        (GAsyncReadyCallback)add_callback, // 콜백 함수
        loop                            // 콜백에 전달할 사용자 데이터
    );
    
    // 메인 루프 실행 (Add 호출 완료까지 대기)
    g_main_loop_run(loop);
    
    // Sub 메서드 비동기 호출
    printf("Calling Sub(5.0, 2.0) asynchronously...\n");
    g_dbus_connection_call(
        connection,
        "org.example.CalculatorService",
        "/org/example/Calculator",
        "org.example.Calculator",
        "Sub",
        g_variant_new("(dd)", 5.0, 2.0),
        G_VARIANT_TYPE("(d)"),
        G_DBUS_CALL_FLAGS_NONE,
        -1,
        NULL,
        (GAsyncReadyCallback)sub_callback,
        loop
    );
    
    // 메인 루프 실행 (Sub 호출 완료까지 대기)
    g_main_loop_run(loop);
    
    // 리소스 정리
    g_object_unref(connection);
    g_main_loop_unref(loop);
    
    return 0;
}

 

반응형