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

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로 항시 돌아 가며 시스템에 접근하는 프로그램이기 때문에 사용 시 많은 테스트와 올바르게 동작 하는지 확인을 하셔야 합니다.

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

모든 댓글을 환영합니다. (욕설과 광고는 삭제합니다.)
  1. Favicon of http://hazedic.org BlogIcon h4z3dic 2007.10.10 18:48  댓글주소  수정/삭제  댓글쓰기

    새로운 글이네용~~ㅎㅎ

  2. Favicon of http://hazedic.org BlogIcon h4z3dic 2007.10.12 18:05  댓글주소  수정/삭제  댓글쓰기

    루비온레일스를 공부하려고 설치했었는데 맥에선 리눅스랑 비교도 안되게 빠르게 설치가 가능하더라구요 패키지로 되어있어서 ㅎㅎㅎ 좋은 강좌 감사합니다!!!

    • h4z3dic 2007.10.12 18:08  댓글주소  수정/삭제

      위에 글에 대한 댓글인데..ㅡㅡ; 이상하게 올라갔네여.. 패스워드가 틀리다고 해서 수정을 못하네요..ㅡㅡ; 지송..

    • Favicon of https://www.cocoadev.co.kr BlogIcon cocoadev 2007.10.12 18:50 신고  댓글주소  수정/삭제

      어디 달렸든 달아 주신 것만 해도 감사하죠. ^^; 루비온레일스. 저도 관심이 많은데... 좀 더 늙은 후에 한가해 지면 봐야겠습니다.

  3. Favicon of http://hazedic.org BlogIcon h4z3dic 2007.10.13 10:28  댓글주소  수정/삭제  댓글쓰기

    요즘 주력 언어 + 유틸리티 언어 한가지 정도는 기본이드라고요.. 공부할게 너무 많아요~ㅠㅠ

  4. atomlee 2012.06.26 18:23  댓글주소  수정/삭제  댓글쓰기

    이거 C언어지요
    리눅스에서 어떻게 실행 하나요?

    gcc 파일명.c로 하여야 하나요?
    죄송합니다. 필요한데, 아직 초보라서요... 부탁드립니다.

  5. atomlee 2012.06.27 06:39  댓글주소  수정/삭제  댓글쓰기

    실행방법은 알았습니다.
    제 리눅스서버에서 돌렸습니다.
    /DDNS/Bin/ServerLinux/에 있는 프로그램을
    nohup ./server &로 실행시키면 잘 됩니다.
    그러나 시간이 지나면 프로세서가 자꾸 죽어서 자동으로 재실행 시키고 싶어서 위의 소스에서
    경로명과 실행파일명만 바꾸어서 실행하였는데 아래와 같이 나옵니다.
    [root@localhost ServerLinux]# ./s_guard.out
    START
    DIE: 2012/6/26 22:14:25
    RELOAD: 2012/6/26 22:14:25
    nohup: appending output to `nohup.out'
    nohup: cannot run command `/DDNS/Bin/ServerLinux/': Permission denied

    여기에서 Permission denied 가 왜 나오는지 궁금합니다.

    권한 설정은
    [root@localhost ServerLinux]# ls -al
    total 172
    drwxr-xr-x 2 root root 4096 Jun 26 22:13 .
    drwxr-xr-x 6 root root 4096 May 31 18:03 ..
    -rw------- 1 root root 680 Jun 26 22:14 nohup.out
    -rwxrwxrwx 1 root root 126599 Jun 4 21:44 server
    -rw-r--r-- 1 root root 1721 Jun 2 09:57 server.conf
    -rwx------ 1 root root 2574 Jun 26 22:13 s_guard.c
    -rwxr-xr-x 1 root root 6880 Jun 26 22:13 s_guard.out
    server의 실행권한을 777로도 해보았고, 755, 700으로도 해보았는데
    동일한 메시지가 나옵니다.
    한수 지도해 주시기 바랍니다.