Skip to content
 

리눅스 데몬 개발 2/8

2단계 : signal()

통신 프로그램 생각할때 먼저 떠올리는건 서버와 클라이언트 즉 리눅스와 윈도우 아니면 서버가 서버의 통신을 생각한다.
통신은 이렇게 두개의 프로그램 또는 다른 서버간에 통신뿐 아니라 1단계에서 말한 프로세서간 내부 통신도 매우 중요한 부분이다.

통신 프로그램을 짤때 단순히 클라이언트가 서버에 접속해서 데이타를 요청하고 받는 단순 구조인 경우라면 크게 신경을 안써도 되겠지만 만일 접속된 클라이언트간에 데이타를 주고 받는 상황이라면 내부 프로세서가 통신은 매우 중요한 부분이다.
게임 프로그램이나 메신저와 같이 클라이언트간에 데이타를 주고 받거나 또는 시스템 상에서 데몬의 종료나 환경 변수의 변경등을 알려주는 기능도 내부 통신이라고 할 수 있다.

아파치 웹서버의 파라메터나 도메인 정보가 바뀌었을때 데몬을 재 시작해도 상관없지만 보통의 경우는 killall -HUP httpd 이런식으로 해당 데몬에게 신호를 주는 방식도 있다.

내부 프로세서가 통신은 IPC라고 하는 칭하는데 3가지의 형태가 있다.
1. tcp, udp, pipe와 같이 데이타를 전송하는 방식
2. semaphore, mutex 와 같이 데이타 동기를 맞추는 방식
3. signal, wait 과 같이 신호를 전송하는 방식
더 많은 분류와 함수도 있겠지만 그 목적별로 나눈다면 위의 가지수가 될것이다.

이번에 설명하는 signal은 데모을 만들때 중요한 기능이므로 우선 설명하기로 한다.

예제 프로그램은 kill 호출이 되기전까지는 1초씩 기다리면서 무한루프를 도는 구조이다. SIGINT는 Ctrl+C를 막는 기능이고 SIGHUP은 일반적으로 프로그램에게 외부 환경 파일이 변경됨을 알려주는 기능으로 많이 사용한다. SIGTERM은 kill 신호를 받았을때 바로 죽지 않고 종료를 안전하게 처리하는 기능을 수행한다.

정확한 코딩방식으로는 signal로 받은 함수를 원상 복귀시키는 로직도 포함이 되어야 하지만 일반적으로 프로그램이 종료하면 자동 복귀가 되므로 생략하는 경우가 많다.

SIGCHILD는 fork로 생성된 프로세서가 종료될때 부모프로세서에게 종료됨을 알리고 부모가 wait도는 waitpid 형태의 함수를 호출해서 종료 상황을 인식할 수 있도록 프로그램을 짤 수 있다.

하지만 SIG_IGN 를 지정하면 해당 신호를 무시하여 간단히 처리하는것도 방법이다. 이렇게 처리하면 fork()로 생성된 child 가 종료시 defunct 형태로 ps 로 확인되는 zombi 프로세서의 생성을 자동적으로 처리해주는 기능을 수행하게 된다.

alarm 함수는 SIGALM을 호출하게 되어 타이머로서 이용할 수 있다.
block 모드로 동작하는 read, write, select 와 같은 함수에서 해당 기능을 이용하면 데이타 전송시 무한 대기로 빠지는 것을 방지할 수 있다.

단 kill -9 와 같이 강제 종료의 경우는 신호가 잡히지 않고 강제 종료가 되게 되므로 일반적인 kill 신호로 데몬을 종료시키면서 안전하게 종료하는 방법으로 개발해야 한다.

예제 프로그램을 실행하고나서 Ctrl+C 키를 누르거나 다른 텔넷창에서 kill -HUP process-id 과같이 테스트를 해볼 수 있다.

#include <stdio.h> 
#include <stdlib.h> 
#include <unistd.h> 
#include <signal.h>  

int sig = 0;  

void sigRtn( int s ) 
{ 
    sig = s; 
    printf( "Receive signal : %d 
", sig ); 
}  

void main() 
{ 
    signal( SIGINT,  sigRtn ); 
    signal( SIGHUP,  sigRtn ); 
    signal( SIGTERM, sigRtn ); 
    signal( SIGALRM, sigRtn ); 
    signal( SIGCHILD, SIG_IGN );  

    alarm( 10 );  

    while( sig != SIGTERM ) 
    { 
        sleep( 1 ); 
    }  

    printf( "Receive kill 
" ); 
}

Leave a Reply