Linux에서 데몬 만들기


110

Linux에서는 중지 할 수없고 파일 시스템 변경을 모니터링하는 데몬을 추가하고 싶습니다. 변경 사항이 감지되면 시작된 콘솔 경로와 개행 문자를 기록해야합니다.

이미 파일 시스템 변경 코드가 거의 준비되어 있지만 데몬을 만드는 방법을 알 수 없습니다.

내 코드는 여기에 있습니다 : http://www.yolinux.com/TUTORIALS/ForkExecProcesses.html

포크 후에 무엇을해야합니까?

int main (int argc, char **argv) {

  pid_t pID = fork();
  if (pID == 0)  {              // child
          // Code only executed by child process    
      sIdentifier = "Child Process: ";
    }
    else if (pID < 0) {
        cerr << "Failed to fork" << endl;
        exit(1);
       // Throw exception
    }
    else                                   // parent
    {
      // Code only executed by parent process

      sIdentifier = "Parent Process:";
    }       

    return 0;
}



POSIX 준수가 필요하지 않은 경우 inotifyAPI에 관심이있을 수 있습니다 . 참조 : inotify_init, inotify_add_watch, inotify_rm_watch.
patryk.beza

답변:


216

Linux에서 중지 할 수없고 파일 시스템 변경을 모니터링하는 데몬을 추가하고 싶습니다. 변경 사항이 감지되면 시작된 콘솔 경로 + 개행 문자를 작성해야합니다.

데몬은 백그라운드에서 작동하며 (보통 ...) TTY에 속하지 않기 때문에 원하는 방식으로 stdout / stderr를 사용할 수 없습니다. 일반적으로 syslog 데몬 ( syslogd )은 파일 (디버그, 오류 등)에 메시지를 기록하는 데 사용됩니다.

그 외에도 프로세스를 데몬 화하는 데 필요한 몇 가지 단계 가 있습니다.


올바르게 기억하는 경우 다음 단계는 다음과 같습니다.

  • 부모 프로세스를 포크 하고 포크가 성공하면 종료합니다. -> 상위 프로세스가 종료되었으므로 이제 하위 프로세스가 백그라운드에서 실행됩니다.
  • setsid- 새 세션을 만듭니다. 호출 프로세스는 새 세션의 리더가되고 새 프로세스 그룹의 프로세스 그룹 리더가됩니다. 이제 프로세스가 제어 터미널 (CTTY)에서 분리됩니다.
  • 신호 포착 - 신호를 무시 및 / 또는 처리합니다.
  • 다시 포크 하고 부모 프로세스를 종료하여 세션 선행 프로세스를 제거하십시오. (세션 리더 만이 TTY를 다시받을 수 있습니다.)
  • chdir- 데몬의 작업 디렉토리를 변경합니다.
  • umask- 데몬의 필요에 따라 파일 모드 마스크를 변경합니다.
  • close- 상위 프로세스에서 상속 될 수있는 모든 열린 파일 설명자를 닫 습니다 .

시작점을 제공하려면 : 기본 단계를 보여주는 스켈레톤 코드를보십시오. 이 코드는 이제 GitHub : Linux 데몬의 기본 골격 에서도 분기 할 수 있습니다.

/*
 * daemonize.c
 * This example daemonizes a process, writes a few log messages,
 * sleeps 20 seconds and terminates afterwards.
 */

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <syslog.h>

static void skeleton_daemon()
{
    pid_t pid;

    /* Fork off the parent process */
    pid = fork();

    /* An error occurred */
    if (pid < 0)
        exit(EXIT_FAILURE);

    /* Success: Let the parent terminate */
    if (pid > 0)
        exit(EXIT_SUCCESS);

    /* On success: The child process becomes session leader */
    if (setsid() < 0)
        exit(EXIT_FAILURE);

    /* Catch, ignore and handle signals */
    //TODO: Implement a working signal handler */
    signal(SIGCHLD, SIG_IGN);
    signal(SIGHUP, SIG_IGN);

    /* Fork off for the second time*/
    pid = fork();

    /* An error occurred */
    if (pid < 0)
        exit(EXIT_FAILURE);

    /* Success: Let the parent terminate */
    if (pid > 0)
        exit(EXIT_SUCCESS);

    /* Set new file permissions */
    umask(0);

    /* Change the working directory to the root directory */
    /* or another appropriated directory */
    chdir("/");

    /* Close all open file descriptors */
    int x;
    for (x = sysconf(_SC_OPEN_MAX); x>=0; x--)
    {
        close (x);
    }

    /* Open the log file */
    openlog ("firstdaemon", LOG_PID, LOG_DAEMON);
}
int main()
{
    skeleton_daemon();

    while (1)
    {
        //TODO: Insert daemon code here.
        syslog (LOG_NOTICE, "First daemon started.");
        sleep (20);
        break;
    }

    syslog (LOG_NOTICE, "First daemon terminated.");
    closelog();

    return EXIT_SUCCESS;
}


  • 코드를 컴파일합니다. gcc -o firstdaemon daemonize.c
  • 데몬을 시작합니다. ./firstdaemon
  • 모든 것이 제대로 작동하는지 확인하십시오. ps -xj | grep firstdaemon

  • 출력은 다음과 유사해야합니다.

+ ------ + ------ + ------ + ------ + ----- + ------- + ------ + ------ + ------ + ----- +
| PPID | PID | PGID | SID | TTY | TPGID | 통계 | UID | 시간 | CMD |
+ ------ + ------ + ------ + ------ + ----- + ------- + ------ + ------ + ------ + ----- +
| 1 | 3387 | 3386 | 3386 | ? | -1 | S | 1000 | 0:00 | ./ |
+ ------ + ------ + ------ + ------ + ----- + ------- + ------ + ------ + ------ + ----- +

여기서 확인해야 할 것은 다음과 같습니다.

  • 데몬에는 제어 터미널이 없습니다 ( TTY =? )
  • 상위 프로세스 ID ( PPID )는 1 (초기 프로세스)입니다.
  • PID! = SID 우리의 프로세스가 세션 리더되지 않음을 의미합니다
    (때문에 두 번째 포크 ())
  • PID! = SID 때문에 우리 프로세스 는 TTY를 다시 제어 할 수 없습니다.

syslog 읽기 :

  • syslog 파일을 찾습니다. 내 위치 :/var/log/syslog
  • 다음을 수행하십시오. grep firstdaemon /var/log/syslog

  • 출력은 다음과 유사해야합니다.

  firstdaemon [3387] : 첫 번째 데몬이 시작되었습니다.
  firstdaemon [3387] : 첫 번째 데몬이 종료되었습니다.


참고 : 실제로 신호 처리기를 구현하고 로깅을 적절하게 설정해야합니다 (파일, 로그 수준 ...).

추가 읽기 :


와우 감사합니다! 훌륭합니다. 그래서 나는 내 코드를 while 루프에 넣어야하는데 그게 다야?
chrisMe jul.

기본적으로 그렇습니다. 그러나이 코드는 단지 예일뿐입니다. 그것은 전적으로 데몬 프로세스를 사용하여 달성하려는 것에 달려 있습니다. 너무이 답변을 읽어 보시기 바랍니다 : @Edwin
파스칼 Werkl

1
두 번째 대신 fork()왜 그냥 사용하지 setsid()않습니까?
Chimera 2013

1
참고 것을 기능 신호들을 제어하는보다 포괄적이고 신뢰성있는 메카니즘을 제공한다; 새로운 응용 프로그램을 사용해야 보다는 . sigaction()sigaction()signal()
patryk.beza

4
이 방법은 "오래된"방법이라는 점을 시청자에게 알려야합니다. 데몬을 만드는 새로운 권장 방법은 여기에있는 "새 스타일 데몬"을 사용하는 것입니다. 0pointer.de/public/systemd-man/daemon.html#New-Style%20Daemons 또는
Starlord

30

man 7 daemon데몬을 만드는 방법을 자세히 설명합니다. 내 대답은이 설명서에서 발췌 한 것입니다.

데몬에는 최소한 두 가지 유형이 있습니다.

  1. 기존 SysV 데몬 ( 구식 ),
  2. systemd 데몬 ( new-style ).

SysV 데몬

기존 SysV 데몬에 관심이있는 경우 다음 단계를 구현해야 합니다 .

  1. 표준 입력 , 출력오류 (즉, 처음 세 개의 파일 설명자 0, 1, 2)를 제외한 모든 열린 파일 설명자를 닫습니다 . 이는 실수로 전달 된 파일 설명자가 데몬 프로세스에 남아 있지 않도록합니다. Linux에서는 /proc/self/fd파일 설명자 3에서 getrlimit()for에서 반환 한 값으로의 반복을 대체 하여를 반복하여 구현하는 것이 가장 좋습니다 RLIMIT_NOFILE.
  2. 모든 신호 처리기를 기본값으로 재설정 합니다. 사용 가능한 신호를 최대 한도까지 반복 _NSIG하고로 재설정하는 것이 가장 좋습니다 SIG_DFL.
  3. 를 사용하여 신호 마스크를 재설정합니다 sigprocmask().
  4. 데몬 런타임에 부정적인 영향을 미칠 수있는 환경 변수를 제거하거나 재설정하여 환경 블록을 삭제합니다.
  5. 를 호출 fork()하여 백그라운드 프로세스를 만듭니다.
  6. 자식 setsid()에서 모든 터미널에서 분리하고 독립적 인 세션을 만들기 위해 호출 합니다 .
  7. 자식에서 fork()다시 호출 하여 데몬이 터미널을 다시 획득 할 수 없도록합니다.
  8. exit()첫 번째 자식을 호출 하여 두 번째 자식 (실제 데몬 프로세스) 만 유지되도록합니다. 이렇게하면 모든 데몬이 그래야하는 것처럼 데몬 프로세스가 init / PID 1의 상위가됩니다.
  9. 데몬 프로세스에서 /dev/null표준 input , outputerror에 연결 합니다 .
  10. 데몬 과정에서,를 다시 umask파일 모드가 통과 그래서, 0 open(), mkdir()직접 만든 파일과 디렉토리의 액세스 모드를 제어 그와 같은.
  11. 데몬 프로세스 에서 현재 디렉토리를 루트 디렉토리 ( ) 로 변경/ 하여 데몬이 마운트 지점이 마운트 해제되는 것을 무의식적으로 차단하지 않도록합니다.
  12. 데몬 프로세스에서 데몬 PID (에서 반환 된대로 getpid())를 PID 파일 /run/foobar.pid( 예 : 가상 데몬 "foobar"의 경우)에 기록하여 데몬이 두 번 이상 시작되지 않도록합니다. PID 파일에 이전에 저장된 PID가 더 이상 존재하지 않거나 외부 프로세스에 속함과 동시에 PID 파일이 확인 될 때만 PID 파일이 업데이트되도록 경쟁없는 방식으로 구현해야합니다.
  13. 데몬 프로세스에서 가능하고 적용 가능한 경우 권한을 삭제합니다.
  14. 데몬 프로세스에서 초기화가 완료되었음을 시작된 원래 프로세스에 알립니다. 이것은 이름이 지정되지 않은 파이프 또는 첫 번째 이전에 생성 된 유사한 통신 채널을 통해 구현 될 수 있으므로 fork()원본 및 데몬 프로세스 모두에서 사용할 수 있습니다.
  15. exit()원래 프로세스를 호출 하십시오. 데몬을 호출 한 프로세스는 초기화가 완료되고 모든 외부 통신 채널이 설정되고 액세스 가능한 후에exit() 발생 한다는 사실에 의존 할 수 있어야합니다 .

다음 경고에 유의하십시오.

BSD daemon()함수 이러한 단계 의 하위 집합 만 구현하므로 사용 해서는 안됩니다 .

SysV 시스템과의 호환성 을 제공해야하는 데몬은 위에서 언급 한 체계를 구현해야합니다. 그러나 디버깅을 용이하게하고 systemd를 사용하여 시스템으로의 통합을 단순화하기 위해이 동작을 선택 사항으로 만들고 명령 줄 인수를 통해 구성 할 수 있도록하는 것이 좋습니다.

참고 daemon()없는 POSIX의 준수.


새로운 스타일의 데몬

새로운 스타일의 데몬의 경우 다음 단계 를 권장합니다.

  1. 경우 SIGTERM수신 깨끗하게 데몬 종료를 종료합니다.
  2. SIGHUP수신 된 경우 구성 파일을 다시로드하십시오 (적용되는 경우).
  3. 서비스 오류 및 문제를 감지하기 위해 init 시스템에서 사용하므로 기본 데몬 프로세스에서 올바른 종료 코드를 제공하십시오. SysV init 스크립트 에 대한 LSB 권장 사항에 정의 된 종료 코드 체계를 따르는 것이 좋습니다 .
  4. 가능하고 적용 가능한 경우 D-Bus IPC 시스템을 통해 데몬의 제어 인터페이스를 노출하고 초기화의 마지막 단계로 버스 이름을 가져옵니다.
  5. systemd에서 통합 하려면 데몬 시작, 중지 및 유지 관리에 대한 정보를 전달 하는 .service unit 파일을 제공 하십시오. 자세한 내용은 systemd.service(5)을 참조하십시오.
  6. 가능한 한 init 시스템의 기능에 의존하여 파일, 서비스 및 기타 리소스에 대한 데몬 액세스를 제한합니다. 즉, systemd의 경우 자체 구현 대신 systemd의 리소스 제한 제어 에 의존하고 systemd의 권한 삭제 에 의존합니다. 데몬에서 구현하는 대신 코드와 유사합니다. systemd.exec(5)사용 가능한 컨트롤 은 을 참조하십시오 .
  7. 경우 D-버스가 사용하는 D-버스 서비스 활성화에 공급하여 데몬 버스 - 기동하게 구성 파일을 . 여기에는 여러 가지 장점이 있습니다. 데몬이 요청시 느리게 시작될 수 있습니다. 필요한 다른 데몬과 병렬로 시작될 수 있습니다. 이는 병렬화 및 부팅 속도 를 최대화 합니다 . 버스가 활성화 가능한 서비스에 대한 요청을 대기열에 추가하므로 버스 요청을 잃지 않고 실패시 데몬을 다시 시작할 수 있습니다. 자세한 내용은 아래 를 참조하십시오.
  8. 데몬이 소켓을 통해 다른 로컬 프로세스 나 원격 클라이언트에 서비스를 제공하는 경우 아래에 설명 된 체계에 따라 소켓 활성화 가 가능해야 합니다 . D-Bus 활성화와 마찬가지로 이것은 서비스 시작의 병렬화를 개선 할뿐만 아니라 주문형 서비스 시작을 가능하게합니다. 또한 상태 비 저장 프로토콜 (예 : syslog, DNS)의 경우 단일 요청 손실없이 소켓 기반 활성화를 구현하는 데몬을 다시 시작할 수 있습니다. 자세한 내용은 아래 를 참조하십시오.
  9. 해당되는 경우 데몬은 sd_notify(3)인터페이스 를 통해 시작 완료 또는 상태 업데이트에 대해 init 시스템에 알려야합니다 .
  10. syslog()호출을 사용하여 시스템 syslog 서비스에 직접 기록 하는 대신 새로운 스타일의 데몬은를 통해 단순히 표준 오류에 기록하도록 선택할 수 있습니다. fprintf()그런 다음 init 시스템에 의해 syslog로 전달됩니다. 로그 수준이 필요한 경우 Linux 커널 printk()수준 시스템 과 유사한 스타일에 따라 "<4>"(syslog 우선 순위 체계의 로그 수준 4 "WARNING")와 같은 문자열로 개별 로그 행을 접두사로 지정하여 이러한 수준을 인코딩 할 수 있습니다 . 자세한 내용은 sd-daemon(3)및을 참조하십시오 systemd.exec(5).

자세한 내용은 전체를 읽으십시오 man 7 daemon.


11

리눅스에서는 죽일 수없는 프로세스를 만들 수 없습니다. 루트 사용자 (uid = 0)는 프로세스에 신호를 보낼 수 있으며 잡을 수없는 신호는 SIGKILL = 9, SIGSTOP = 19입니다. 그리고 다른 신호 (잡히지 않은 경우)도 프로세스를 종료 할 수 있습니다.

프로그램 / 데몬의 이름과 프로그램을 실행할 경로 (예 : "/"또는 "/ tmp")를 지정할 수있는보다 일반적인 데몬 화 기능이 필요할 수 있습니다. stderr 및 stdout (및 stdin을 사용하는 제어 경로)에 대한 파일을 제공 할 수도 있습니다.

필요한 것은 다음과 같습니다.

#include <stdio.h>    //printf(3)
#include <stdlib.h>   //exit(3)
#include <unistd.h>   //fork(3), chdir(3), sysconf(3)
#include <signal.h>   //signal(3)
#include <sys/stat.h> //umask(3)
#include <syslog.h>   //syslog(3), openlog(3), closelog(3)

여기 더 일반적인 기능이 있습니다.

int
daemonize(char* name, char* path, char* outfile, char* errfile, char* infile )
{
    if(!path) { path="/"; }
    if(!name) { name="medaemon"; }
    if(!infile) { infile="/dev/null"; }
    if(!outfile) { outfile="/dev/null"; }
    if(!errfile) { errfile="/dev/null"; }
    //printf("%s %s %s %s\n",name,path,outfile,infile);
    pid_t child;
    //fork, detach from process group leader
    if( (child=fork())<0 ) { //failed fork
        fprintf(stderr,"error: failed fork\n");
        exit(EXIT_FAILURE);
    }
    if (child>0) { //parent
        exit(EXIT_SUCCESS);
    }
    if( setsid()<0 ) { //failed to become session leader
        fprintf(stderr,"error: failed setsid\n");
        exit(EXIT_FAILURE);
    }

    //catch/ignore signals
    signal(SIGCHLD,SIG_IGN);
    signal(SIGHUP,SIG_IGN);

    //fork second time
    if ( (child=fork())<0) { //failed fork
        fprintf(stderr,"error: failed fork\n");
        exit(EXIT_FAILURE);
    }
    if( child>0 ) { //parent
        exit(EXIT_SUCCESS);
    }

    //new file permissions
    umask(0);
    //change to path directory
    chdir(path);

    //Close all open file descriptors
    int fd;
    for( fd=sysconf(_SC_OPEN_MAX); fd>0; --fd )
    {
        close(fd);
    }

    //reopen stdin, stdout, stderr
    stdin=fopen(infile,"r");   //fd=0
    stdout=fopen(outfile,"w+");  //fd=1
    stderr=fopen(errfile,"w+");  //fd=2

    //open syslog
    openlog(name,LOG_PID,LOG_DAEMON);
    return(0);
}

다음은 데몬이되어 주위를 맴돌다가 떠나는 샘플 프로그램입니다.

int
main()
{
    int res;
    int ttl=120;
    int delay=5;
    if( (res=daemonize("mydaemon","/tmp",NULL,NULL,NULL)) != 0 ) {
        fprintf(stderr,"error: daemonize failed\n");
        exit(EXIT_FAILURE);
    }
    while( ttl>0 ) {
        //daemon code here
        syslog(LOG_NOTICE,"daemon ttl %d",ttl);
        sleep(delay);
        ttl-=delay;
    }
    syslog(LOG_NOTICE,"daemon ttl expired");
    closelog();
    return(EXIT_SUCCESS);
}

SIG_IGN은 신호를 포착하고 무시 함을 나타냅니다. 신호 수신을 기록 할 수있는 신호 처리기를 빌드하고 플래그 (예 : 정상 종료를 나타내는 플래그)를 설정할 수 있습니다.


8

daemon기능을 사용해보십시오 :

#include <unistd.h>

int daemon(int nochdir, int noclose);

로부터 man 페이지 :

daemon () 함수는 제어 터미널에서 자신을 분리하고 시스템 데몬으로 백그라운드에서 실행하려는 프로그램을위한 것입니다.

nochdir이 0이면 daemon ()은 호출 프로세스의 현재 작업 디렉토리를 루트 디렉토리 ( "/")로 변경합니다. 그렇지 않으면 현재 작업 디렉토리가 변경되지 않습니다.

noclose가 0이면 daemon ()은 표준 입력, 표준 출력 및 표준 오류를 / dev / null로 리디렉션합니다. 그렇지 않으면 이러한 파일 설명자가 변경되지 않습니다.


2
참고 daemon(7)매뉴얼은 데몬을 작성하는 단계를 언급하고 있다고 경고 : BSD의 daemon()그 다음 단계의 하위 집합 만 구현과 같은 기능을 사용할 수 없습니다. daemon함수는 먼저 등장 4.4BSD 이고 하지 POSIX 호환 .
patryk.beza

2
또한 daemon () 사용에 대한 경고는 daemon (7) 매뉴얼 페이지 의 이전 스타일 SysV 섹션에 있습니다. systemd의 경우 daemon () 사용을 권장하지 않습니다.
그렉 McPherran

7

" 멈출 수없는 데몬 ..." 이라는 첫 번째 요구 사항에서 멈출 수 있습니다 .

내 친구는 불가능합니다. 그러나 훨씬 더 나은 도구 인 커널 모듈을 사용하여 동일한 결과를 얻을 수 있습니다.

http://www.infoq.com/articles/inotify-linux-file-system-event-monitoring

모든 데몬을 중지 할 수 있습니다. 일부는 다른 것보다 더 쉽게 중지됩니다. 보류중인 파트너와의 데몬 쌍도 잃어버린 경우 파트너를 리스폰하는 것을 중지 할 수 있습니다. 당신은 그것에 대해 조금 더 열심히 일해야합니다.


7
저자는 "멈출 수없는 데몬"이라고 말하면 실제로 세션이 종료 될 때 데몬이 항상 백그라운드에서 실행 중임을 의미합니다.
FaceBro 2014 년

6

앱이 다음 중 하나 인 경우 :

{
  ".sh": "bash",
  ".py": "python",
  ".rb": "ruby",
  ".coffee" : "coffee",
  ".php": "php",
  ".pl" : "perl",
  ".js" : "node"
}

NodeJS 종속성에 신경 쓰지 않고 NodeJS를 설치하고 다음을 수행하십시오.

npm install -g pm2

pm2 start yourapp.yourext --name "fred" # where .yourext is one of the above

pm2 start yourapp.yourext -i 0 --name "fred" # run your app on all cores

pm2 list

재부팅시 모든 앱을 계속 실행하려면 (및 pm2 데몬 화) :

pm2 startup

pm2 save

이제 다음을 수행 할 수 있습니다.

service pm2 stop|restart|start|status

(또한 쉽게 앱 디렉토리에서 코드 변경을 감시하고 코드 변경이 발생하면 앱 프로세스를 자동으로 다시 시작할 수 있습니다)


2
이것은 C.와는 아무 상관이 없다
멜 포메 네

4
C 태그가있어 감사합니다. 그러나 OP는 질문에서 C와 관련된 요구 사항을 언급하지 않습니다. 제목은 리눅스에서 악마를 만드는 것입니다. 이 대답은 그것을 만족시킵니다.
danday74

1
오, 맞아요. 태그가 C이지만 실제 요구 사항은 C ++입니다 (OP의 코드와 링크 된 기사에서 알 수 있듯이).
멜 포메 네

3

fork ()를 호출하여 자식 프로세스를 만들었습니다. 포크가 성공하면 (포크가 0이 아닌 PID를 반환 함) 자식 프로세스 내에서이 지점부터 실행이 계속됩니다. 이 경우 부모 프로세스를 정상적으로 종료 한 다음 자식 프로세스에서 작업을 계속하려고합니다.

아마도 이것이 도움이 될 것입니다 : http://www.netzmafia.de/skripten/unix/linux-daemon-howto.html


2

데몬은 백그라운드에있는 프로세스 일뿐입니다. OS가 부팅 될 때 프로그램을 시작하려면 Linux에서 /etc/rc.d/rc.local (다른 모든 스크립트 이후 실행) 또는 /etc/startup.sh에 시작 명령을 추가합니다.

Windows에서는 서비스를 만들고 서비스를 등록한 다음 관리-> 서비스 패널에서 부팅시 자동으로 시작되도록 설정합니다.


1
감사. 그렇다면 "데몬"과 일반 프로그램간에 차이가 없습니까? 나는 그것이 쉽게 닫히기를 원하지 않는다.
chrisMe

1
아니요, 데몬은 단지 백그라운드 프로세스입니다. 더 구체적으로 말하자면, 부모로부터 포크하고 자식 프로세스를 실행하고 부모를 종료합니다 (프로그램에 대한 터미널 액세스가 없도록). "데몬"이 되려면 그다지 필요하지 않습니다. en.wikipedia.org/wiki/Daemon_(computing)
Magn3s1um

1

데몬 템플릿

나는 새로운 스타일의 데몬 다음 데몬 템플릿을 작성 : 링크를

GitHub에서 전체 템플릿 코드를 찾을 수 있습니다. 여기

Main.cpp

// This function will be called when the daemon receive a SIGHUP signal.
void reload() {
    LOG_INFO("Reload function called.");
}

int main(int argc, char **argv) {
    // The Daemon class is a singleton to avoid be instantiate more than once
    Daemon& daemon = Daemon::instance();
    // Set the reload function to be called in case of receiving a SIGHUP signal
    daemon.setReloadFunction(reload);
    // Daemon main loop
    int count = 0;
    while(daemon.IsRunning()) {
        LOG_DEBUG("Count: ", count++);
        std::this_thread::sleep_for(std::chrono::seconds(1));
    }
    LOG_INFO("The daemon process ended gracefully.");
}

Daemon.hpp

class Daemon {
    public:

    static Daemon& instance() {
        static Daemon instance;
        return instance;
    }

    void setReloadFunction(std::function<void()> func);

    bool IsRunning();

    private:

    std::function<void()> m_reloadFunc;
    bool m_isRunning;
    bool m_reload;

    Daemon();
    Daemon(Daemon const&) = delete;
    void operator=(Daemon const&) = delete;

    void Reload();

    static void signalHandler(int signal);
};

Daemon.cpp

Daemon::Daemon() {
    m_isRunning = true;
    m_reload = false;
    signal(SIGINT, Daemon::signalHandler);
    signal(SIGTERM, Daemon::signalHandler);
    signal(SIGHUP, Daemon::signalHandler);
}

void Daemon::setReloadFunction(std::function<void()> func) {
    m_reloadFunc = func;
}

bool Daemon::IsRunning() {
    if (m_reload) {
        m_reload = false;
        m_reloadFunc();
    }
    return m_isRunning;
}

void Daemon::signalHandler(int signal) {
    LOG_INFO("Interrup signal number [", signal,"] recived.");
    switch(signal) {
        case SIGINT:
        case SIGTERM: {
            Daemon::instance().m_isRunning = false;
            break;
        }
        case SIGHUP: {
            Daemon::instance().m_reload = true;
            break;
        }
    }
}

daemon-template.service

[Unit]
Description=Simple daemon template
After=network.taget

[Service]
Type=simple
ExecStart=/usr/bin/daemon-template --conf_file /etc/daemon-template/daemon-tenplate.conf
ExecReload=/bin/kill -HUP $MAINPID
User=root
StandardOutput=syslog
StandardError=syslog
SyslogIdentifier=daemon-template

[Install]
WantedBy=multi-user.target
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.