이 글은 GTK를 사용하는 데 있어서 필요한 사항들에 대해 직접 사용해본 경험을 소개하는 글로 누구에게라도 도움이 되지 않을 까 해서 올려봅니다.
/* 소켓에서 읽을 데이터가 있을 경우 호출될 콜백 함수 */
static void client_signal_handler_threaded(GIOChannel *channel, GIOCondition condition, GtkEntry *entry )
{
gchar message[MAX_MSG_LEN];
gsize length;
g_io_channel_read_chars (channel, message, MAX_MSG_LEN, &length, NULL); printf("client_signal_handler_threaded: Received: %s",message);
}
int init_giochannle(int fd, tDTUN_PROCESS_HANDLER1 handler)
{
/* GIOChannel 생성 */

gtk에서 별도의 쓰레드를 만들지 않고 간단하게 소켓통신 기능을 추가하려고 한다면 GIOChannel이 그 대안이 될 수 있다.
리눅스에서 GTK 프로그래밍 할때 대부분의 애플리케이션은 다음과 같은 초기화부분과 하나의 회돌이(loop)를 가진다
/* 주 윈도우 만들기 */
MainWindow = create_dialog1();
gtk_widget_show (MainWindow);
/* 애플리케이션 종료 신호에 대한 콜백 설정하기 */
g_signal_connect ((gpointer) MainWindow, "destroy", G_CALLBACK(gtk_main_quit), NULL);
g_signal_connect (MainWindow, "delete_event", gtk_main_quit, NULL); /* dirty */
/* 필요한 위젯 추가하기 */
//GtkMsg_Init(MainWindow);
/* MainWindow에 달린 모든 위젯 표시 */
gtk_widget_show_all (MainWindow);
/* 종료신호가 콜백함수에서 처리될때 까지의 무한 회돌이 */
gtk_main();
애플리케이션이 이러한 구조를 가질때 소켓통신 기능을 추가하려고 한다면 어떻게 해야 하는가?
일반적으로 소켓 통신을 하기 위해서는 별도의 쓰레드를 만들어서 사용하게 되는데 쓰레드의 관리가 싫은 경우 쓰레드의 생성없이 비슷한 효과를 낼 수 있도록 하기 위해 리눅스에서는 poll()함수를 이용한 GIOChannel을 지원한다.
다음은 GIOChannel의 사용예이다.
/* 소켓에서 읽을 데이터가 있을 경우 호출될 콜백 함수 */
static void client_signal_handler_threaded(GIOChannel *channel, GIOCondition condition, GtkEntry *entry )
{
gchar message[MAX_MSG_LEN];
gsize length;
g_io_channel_read_chars (channel, message, MAX_MSG_LEN, &length, NULL); printf("client_signal_handler_threaded: Received: %s",message);
}
int init_giochannle(int fd, tDTUN_PROCESS_HANDLER1 handler)
{
/* GIOChannel 생성 */
ctl_io = g_io_channel_unix_new(fd);
if ( ctl_io == NULL )
{
error("create_subprocess: error => failed to create a new GIOChannel.\n");
return -1;
}
g_io_channel_set_encoding ( ctl_io, NULL, NULL);
/* NONBLOCK 속성 설정 */
g_io_channel_set_flags( ctl_io, G_IO_FLAG_APPEND| G_IO_FLAG_NONBLOCK, NULL);
g_io_channel_set_close_on_unref( ctl_io, TRUE);
/* G_IO_IN 이벤트시 호출될 콜백함수 설정 */
result = g_io_add_watch( ctl_io, G_IO_IN, handler, NULL);
if ( !result )
{
error("create_subprocess: error => Cannot add watch on GIOChannel=%d.\n", ctl_io); perror("g_io_add_watch");
}
{
error("create_subprocess: error => failed to create a new GIOChannel.\n");
return -1;
}
g_io_channel_set_encoding ( ctl_io, NULL, NULL);
/* NONBLOCK 속성 설정 */
g_io_channel_set_flags( ctl_io, G_IO_FLAG_APPEND| G_IO_FLAG_NONBLOCK, NULL);
g_io_channel_set_close_on_unref( ctl_io, TRUE);
/* G_IO_IN 이벤트시 호출될 콜백함수 설정 */
result = g_io_add_watch( ctl_io, G_IO_IN, handler, NULL);
if ( !result )
{
error("create_subprocess: error => Cannot add watch on GIOChannel=%d.\n", ctl_io); perror("g_io_add_watch");
}
}
main() {
main() {
..........
loop = g_main_loop_new (NULL, FALSE);
/* Setup for giochannel */
init_giochannle(sockfd, client_signal_handler_threaded);
g_main_loop_run (loop); /* Wheee! */
}
GIOChannel의 사용상 이점은 GTK나 gmain_loop_run()사용시 별도의 쓰레드를 사용하지 않고 비정기적으로 발생되는 이벤트에 대해서 처리가 가능하다는 점이다. 또 주 회돌이에서 빈번하게 타이머등을 사용하여 해당 이벤트를 검사하지 않고, 콜백함수를 호출하도록만 설정해놓음으로서 코드가 간결해 진다는 점에 있다.