반응형




<!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="com.example.FileSystemMonitor">
    <!-- 파일 변경 시그널 -->
    <signal name="FileChanged">
      <arg type="s" name="path" direction="out"/>
      <arg type="s" name="event_type" direction="out"/>
    </signal>
    
    <!-- 파일 생성 시그널 -->
    <signal name="FileCreated">
      <arg type="s" name="path" direction="out"/>
      <arg type="t" name="size" direction="out"/>
    </signal>
    
    <!-- 디렉토리 변경 시그널 -->
    <signal name="DirectoryChanged">
      <arg type="s" name="path" direction="out"/>
      <arg type="i" name="num_files" direction="out"/>
    </signal>
  </interface>
</node>


fs-monitor-server.c

#include <gio/gio.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

static GDBusConnection *connection = NULL;

// 파일 변경 시그널 발송
static void
emit_file_changed(const char *path, const char *event_type)
{
  GError *error = NULL;
  
  gboolean result = g_dbus_connection_emit_signal(
      connection,
      NULL,  // destination (NULL = broadcast)
      "/com/example/FileSystemMonitor",
      "com.example.FileSystemMonitor",
      "FileChanged",
      g_variant_new("(ss)", path, event_type),
      &error);
  
  if (!result) {
    g_printerr("Failed to emit signal: %s\n", error->message);
    g_error_free(error);
  } else {
    g_print("Emitted FileChanged: path=%s, event=%s\n", path, event_type);
  }
}

// 디렉토리 변경 시그널 발송
static void
emit_directory_changed(const char *path, gint num_files)
{
  GError *error = NULL;
  
  gboolean result = g_dbus_connection_emit_signal(
      connection,
      NULL,
      "/com/example/FileSystemMonitor",
      "com.example.FileSystemMonitor",
      "DirectoryChanged",
      g_variant_new("(si)", path, num_files),
      &error);
  
  if (!result) {
    g_printerr("Failed to emit signal: %s\n", error->message);
    g_error_free(error);
  } else {
    g_print("Emitted DirectoryChanged: path=%s, files=%d\n", path, num_files);
  }
}

// 주기적으로 다양한 경로에 대한 시그널 발생
static gboolean
simulate_events(gpointer user_data)
{
  static int counter = 0;
  
  switch (counter % 6) {
    case 0:
      emit_file_changed("/home/user/documents/file.txt", "modified");
      break;
    case 1:
      emit_file_changed("/home/user/documents/subdir/data.txt", "created");
      break;
    case 2:
      emit_file_changed("/home/user/pictures/photo.jpg", "modified");
      break;
    case 3:
      emit_directory_changed("/home/user/documents", 15);
      break;
    case 4:
      emit_directory_changed("/home/user/documents/subdir", 5);
      break;
    case 5:
      emit_file_changed("/tmp/test.log", "deleted");
      break;
  }
  
  counter++;
  return TRUE;  // 계속 실행
}

static void
on_bus_acquired(GDBusConnection *conn,
                const gchar *name,
                gpointer user_data)
{
  connection = conn;
  g_print("Bus acquired: %s\n", name);
  g_print("Starting to emit signals...\n\n");
  
  // 2초마다 시그널 발생
  g_timeout_add_seconds(2, simulate_events, NULL);
}

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

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

int main(void)
{
  GMainLoop *loop;
  guint owner_id;
  
  loop = g_main_loop_new(NULL, FALSE);
  
  owner_id = g_bus_own_name(G_BUS_TYPE_SESSION,
                             "com.example.FileSystemMonitor",
                             G_BUS_NAME_OWNER_FLAGS_NONE,
                             on_bus_acquired,
                             on_name_acquired,
                             on_name_lost,
                             loop,
                             NULL);
  
  g_print("FileSystem Monitor Server running...\n");
  g_main_loop_run(loop);
  
  g_bus_unown_name(owner_id);
  g_main_loop_unref(loop);
  
  return 0;
}



fs-monitor-client.c

#include <gio/gio.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

// 시그널 콜백 함수
static void
on_signal_received(GDBusConnection *connection,
                   const gchar *sender_name,
                   const gchar *object_path,
                   const gchar *interface_name,
                   const gchar *signal_name,
                   GVariant *parameters,
                   gpointer user_data)
{
  const gchar *subscription_name = (const gchar *)user_data;
  
  if (g_strcmp0(signal_name, "FileChanged") == 0) {
    const gchar *path, *event_type;
    g_variant_get(parameters, "(&s&s)", &path, &event_type);
    g_print("[%s] FileChanged: path=%s, event=%s\n", 
            subscription_name, path, event_type);
  }
  else if (g_strcmp0(signal_name, "DirectoryChanged") == 0) {
    const gchar *path;
    gint num_files;
    g_variant_get(parameters, "(&si)", &path, &num_files);
    g_print("[%s] DirectoryChanged: path=%s, files=%d\n",
            subscription_name, path, num_files);
  }
}

int main(int argc, char *argv[])
{
  GMainLoop *loop;
  GDBusConnection *connection;
  GError *error = NULL;
  guint subscription_id1, subscription_id2, subscription_id3, subscription_id4;
  
  if (argc != 1) {
    g_printerr("Usage: %s\n", argv[0]);
    return 1;
  }
  
  // D-Bus 연결
  connection = g_bus_get_sync(G_BUS_TYPE_SESSION, NULL, &error);
  if (error != NULL) {
    g_printerr("Failed to connect to bus: %s\n", error->message);
    g_error_free(error);
    return 1;
  }
  
  g_print("Connected to D-Bus. Subscribing to signals...\n\n");
  
  // === 예제 1: 정확한 경로 매칭 (플래그 없음) ===
  g_print("Subscription 1: Exact match for '/home/user/documents/file.txt'\n");
  subscription_id1 = g_dbus_connection_signal_subscribe(
      connection,
      "com.example.FileSystemMonitor",     // sender
      "com.example.FileSystemMonitor",     // interface
      "FileChanged",                        // signal name
      "/com/example/FileSystemMonitor",    // object path
      "/home/user/documents/file.txt",     // arg0 (정확한 매칭만)
      G_DBUS_SIGNAL_FLAGS_NONE,            // 플래그 없음
      on_signal_received,
      g_strdup("SUB1-Exact"),
      g_free);
  
  // === 예제 2: 경로 기반 매칭 (MATCH_ARG0_PATH) ===
  g_print("Subscription 2: Path-based match for '/home/user/documents' (includes subdirs)\n");
  subscription_id2 = g_dbus_connection_signal_subscribe(
      connection,
      "com.example.FileSystemMonitor",
      "com.example.FileSystemMonitor",
      "FileChanged",
      "/com/example/FileSystemMonitor",
      "/home/user/documents",              // arg0 (하위 경로 포함)
      G_DBUS_SIGNAL_FLAGS_MATCH_ARG0_PATH, // ← 핵심 플래그!
      on_signal_received,
      g_strdup("SUB2-Path"),
      g_free);
  
  // === 예제 3: 다른 경로 매칭 ===
  g_print("Subscription 3: Path-based match for '/home/user/pictures'\n");
  subscription_id3 = g_dbus_connection_signal_subscribe(
      connection,
      "com.example.FileSystemMonitor",
      "com.example.FileSystemMonitor",
      "FileChanged",
      "/com/example/FileSystemMonitor",
      "/home/user/pictures",
      G_DBUS_SIGNAL_FLAGS_MATCH_ARG0_PATH,
      on_signal_received,
      g_strdup("SUB3-Pictures"),
      g_free);
  
  // === 예제 4: 모든 DirectoryChanged 시그널 수신 (arg0 필터 없음) ===
  g_print("Subscription 4: All DirectoryChanged signals\n");
  subscription_id4 = g_dbus_connection_signal_subscribe(
      connection,
      "com.example.FileSystemMonitor",
      "com.example.FileSystemMonitor",
      "DirectoryChanged",
      "/com/example/FileSystemMonitor",
      NULL,                                // arg0 필터 없음 (모든 경로)
      G_DBUS_SIGNAL_FLAGS_NONE,
      on_signal_received,
      g_strdup("SUB4-AllDirs"),
      g_free);
  
  g_print("\n=== Listening for signals ===\n\n");
  
  // 메인 루프 실행
  loop = g_main_loop_new(NULL, FALSE);
  g_main_loop_run(loop);
  
  // 정리
  g_dbus_connection_signal_unsubscribe(connection, subscription_id1);
  g_dbus_connection_signal_unsubscribe(connection, subscription_id2);
  g_dbus_connection_signal_unsubscribe(connection, subscription_id3);
  g_dbus_connection_signal_unsubscribe(connection, subscription_id4);
  g_object_unref(connection);
  g_main_loop_unref(loop);
  
  return 0;
}




Makefile

CC = gcc
CFLAGS = $(shell pkg-config --cflags gio-2.0 gio-unix-2.0)
LIBS = $(shell pkg-config --libs gio-2.0 gio-unix-2.0)

all: fs-monitor-server fs-monitor-client

fs-monitor-server: fs-monitor-server.c
	$(CC) -o fs-monitor-server fs-monitor-server.c $(CFLAGS) $(LIBS)

fs-monitor-client: fs-monitor-client.c
	$(CC) -o fs-monitor-client fs-monitor-client.c $(CFLAGS) $(LIBS)

clean:
	rm -f fs-monitor-server fs-monitor-client

.PHONY: all clean



반응형