BLOG ARTICLE 서버 | 1 ARTICLE FOUND

  1. 2007.10.10 특정 프로세스 확인 및 재실행 소스 (리눅스) (9)

이전에 급조해서 만들어 놓았던 리눅스용 서버 프로세스 감시 어플리케이션 소스 입니다. 실행되면 특정 프로세스가 실행 되는지 검사하다 프로세스가 없으면 정해진 파일을 다시 실행합니다.

proc 파일 시스템을 이용하기 때문에 이 소스로는 proc 파일 시스템을 사용하지 않는 맥 OS X에서는 동작하지 않습니다. 현 소스는 Linux에서 사용했고 freeBSD에서도 디렉토리와 몇 가지만 바꾸면 사용하는데 이상이 없을 겁니다. 원래 freeBSD에서 사용했던 것을 Linux로 옮겨 왔습니다.

일단 소스입니다. 보시면 알겠지만 제가 있던 환경만을 생각해서 만들었고, 여러 상황이나 오류에 대한 고려가 없으니 만약 사용 시에는 아래의 사항을 반드시 확인해 보세요.
#include <stdio.h>
#include <string.h>
#include <dirent.h>
#include <unistd.h>
#include <sys/types.h>
#include <time.h>
#include <stdlib.h>
    
/* 검사 주기(초) */
#define CHECK_SECOND        30  

/* 실행 서버 패스 및 이름 */
#define APP_PATH            "/root/ztsvr/ztsvr"
#define APP_NAME            "ztsvr"

int check_process();
void get_timef(time_t, char *);

int main()
{
    int rt;
    time_t  the_time;
    char buffer[255];
    char app[255];

    sprintf(app, "nohup %s &", APP_PATH);

    printf("START\n");
    fflush(stdout);
    while(1)
    {
        time(&the_time);
        get_timef(the_time, buffer);

        rt = check_process();

        if(rt == 0)
        {
            printf("DIE: %s\n", buffer);

            /** 새로 뛰움 **/
            system(app);
            printf("RELOAD: %s\n", buffer);
        }
        else
        {
            printf("OK: %s\n", buffer);
        }

        fflush(stdout);
       
       /* 검사 후, process sleep */
        sleep(CHECK_SECOND);   
    }
    return 0;
}

/** 프로세스 검사 */
int check_process()
{   
    DIR* pdir;
    struct dirent *pinfo;
    int is_live = 0;

    pdir = opendir("/proc");
    if(pdir == NULL)
    {
        printf("err: NO_DIR\n");
        return 0;
    }

    /** /proc 디렉토리의 프로세스 검색 */
    while(1)
    {
        pinfo = readdir(pdir);
        if(pinfo == NULL)
            break;

        /** 파일이거나 ".", "..", 프로세스 디렉토리는 숫자로 시작하기 때문에 아스키코드 57(9)가 넘을 경우 건너뜀 */
        if(pinfo->d_type != 4 || pinfo->d_name[0] == '.' || pinfo->d_name[0] > 57)
            continue;

        FILE* fp;
        char buff[128];
        char path[128];

        sprintf(path, "/proc/%s/status", pinfo->d_name);
        fp = fopen(path, "rt");
        if(fp)
        {
            fgets(buff, 128, fp);
            fclose(fp);

            /** 프로세스명과 status 파일 내용과 비교 */ 
            if(strstr(buff, APP_NAME))
            {
                is_live = 1;
                break;
            }
        }
        else
        {
            printf("Can't read file [%s]\n", path);
        }
    }

    closedir(pdir);

    return is_live;
}

/** 현재 시간을 설정 */
void get_timef(time_t org_time, char *time_str)
{
    struct tm *tm_ptr;
    tm_ptr = localtime(&org_time);

    sprintf(time_str, "%d/%d/%d %d:%d:%d",
                    tm_ptr->tm_year+1900,
                    tm_ptr->tm_mon+1,
                    tm_ptr->tm_mday,
                    tm_ptr->tm_hour,
                    tm_ptr->tm_min,
                    tm_ptr->tm_sec);
}

0. 용도
서버 자체가 든든 해서 어떠한 상황에서도 죽는 일이 없어야 겠지만, 중요한 서비스라면 일단 자동으로 살려 놓고 원인을 찾아야 할 경우를 위해 만들어 놓았습니다.

1. 설정
#define CHECK_SECOND        30  
검사 주기를 초단위로 설정합니다. 이 설정으로는 검사를 한 후 30초 sleep상태로 잠들어 있다 30초 마다 다시 검사합니다.

#define APP_PATH            "/root/ztsvr/ztsvr"
실행해야 될 서버 실행파일의 전체경로와 파일명입니다.

#define APP_NAME            "ztsvr"
실행 프로세스명(파일명) 입니다.

sprintf(app, "nohup %s &", APP_PATH);
system 합수로 실행해야될 명령어를 설정합니다. 참고로 nohup [실행파일 패스] &로 실행을 하면 실행파일은 백그라운드에서 실행되며 터미널의 연결이 종료되어도 계속 실행됩니다.

콘솔 출력 내용은 생성되는 nohup.out 파일 에서 확인할 수 있습니다. 위에서 printf로 출력되는 내용은 모두 nohup.out에 저장됩니다.

2. 주의 사항
if(strstr(buff, APP_NAME))
위와 같이 strstr로 간단한 검사만 합니다. "abc"란 프로세서가 죽었더라도 "abcdef"란 프로세스가 있으면 살아 있는 것으로 간주됩니다.  서버 이름이 절대 중복되지 않으면 상관 없지만, 안전을 위하여, 해당 시스템의 stat 파일의 포멧을 보고 파싱해서 정확하게 검사해야 할 것 입니다.

nohup.out 파일의 크기
검사 주기가 작고 출력되는 내용이 많을 경우에는 nohup.out 파일의 크기가 지나치게 커질 수 있습니다. 콘솔로 출력되는 양을 줄이거나 주기적으로 파일의 크기를 체크해야 합니다.

2000년 초 제작 하여 몇 번을 사용 해 보고 이상이 없었으나, 백그라운드에서 while로 항시 돌아 가며 시스템에 접근하는 프로그램이기 때문에 사용 시 많은 테스트와 올바르게 동작 하는지 확인을 하셔야 합니다.

이 소스를 이용해서 일어나는 피해에 관해서는 일절 책임을 지지 않으니, 주의해서 사용하시기 바랍니다.