카테고리 없음
dbus경로기반 매칭
2025. 11. 21. 10:55반응형
<!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반응형
