1. 데몬(daemon) 이란?
주기적인 서비스 요청을 처리하기 위해서 커널상에 백그라운드 모드로 실행되는 프로세스로, 메모리 관리 방법에 따라 단독 데몬과 xinetd로 분리된다.

  • 단독데몬
    항상 백그라운드 모드로 실행되고 메모리를 상대적으로 많이 소비한다. 그러나 서비스(응답속도)가 빠르다. httpd와 같은 웹서비스 데몬이 대표적.
  • xinetd(슈퍼데몬)
    요청이 있을때마다 xinetd가 서비스를 싱행시켜주므로 메모리 소비가 적다. 그러나 단독데몬에 비해 상대적으로 서비스 속도가 느리다.


2. 간단한 자바 데몬 만들기
nohup을 이용해서 java를 실행시킨다.

터미널이 종료될 때(쉘이 종료될 때) 프로세스가 죽는 이유는 해당 프로세스가 쉘의 자식 프로세스 이기 때문이다. 따라서, 부모 프로세스가 죽을대 던지는 SIGHUP을 자식 프로세스가 받게 된다.

nohup은 부모 프로세스가 죽을때 자식 프로세스에게 SIGHUP을 던지지 않는 프로세스를 말한다.

$ nohup java 클래스명 & 
 
사용하기 편한 장점은 있으나, 문제는 중지를 시킬수 없다. 즉, 해당 프로세스 ID를 찾아내 kill하는 수 밖에 없다. 물론 파일 체크 기법, 소켓을 이용한 제어 방법등을 사용할 수 있지만 스스로 구현해야 하는 번거로움이 있다.


3. apache commons daemon 이용하기
Java는 UNIX의 시그널 처리를 할수 없기때문에, 중지 신호(TERM signal)를 처리하기 위해서는 따로 구현을 해야한다. 이런 번거로움을 해결하기 위해 자카르타의 하위 프로젝트중의 commons daemon을 이용한다. commons daemon은 중지 신호를 받으면 미리 지정된 메소드를 실행한다.


UNIX용 Jsvc와 윈도우용 Procrun 있다.
여기서는 Jsvc를 이용해보도록 하겠다.


commons daemon을 다운로드해 압축을 해제하면 위 그림과 같다.
commons-daemon.jar 파일은 Java프로젝트 lib폴더에 복사해둔다.


bin폴더의 압축파일을 해제하면 jsvc-src라는 폴더가 나온다.
폴더의 내용은 위와 같다.
commons daemon을 사용하기 위해서는 바로 여기서 jsvc를 빌드해줘야 한다.
빌드환경은 다음과 같다.(리눅스에서 빌드해야한다.)

  • GNU AutoConf(at least 2.53)
  • ANSI-C compliant compiler(GCC is good)
  • GNU Make
  • A Java Platform 2 compliant SDK

여기서부터는 ubuntu 8.10 환경에서 진행하도록 한다.

먼저 JDK가 설치되어 있지 않다면 JDK를 설치한다.

 $ sudo apt-get install sun-java6-jdk

JDK가 설치되는 경로는 /usr/lib/jvm/java-6-sun 이다.

gcc 및 make 가 설치되있지 않다면 아래 명령를 이용해 한방에 설치한다.

 $ sudo apt-get install build-essential

AutoConf가 설치되있지 않다면 AutoConf를 설치한다.

 $ sudo apt-get install autoconf

Jsvc를 빌드하는 방법은 다음과 같다.

  • support/buildconf.sh
  • ./configure --with-java=/usr/lib/jvm/java-6-sun
  • make


빌드가 성공적으로 이루어졌다면 위 그림과 같이 jsvc가 만들어진것을 확인할 수 있다. 이후 이 파일을 가지고 Java 데몬을 실행한다.

Java 데몬을 만들려면 org.apache.commons.daemon.Daemon 인터페이스의 init, start, stop, destory 메소드를 구현해야 한다.

샘플 코드는 아래와 같다.
  1. import org.apache.commons.daemon.Daemon;   
  2. import org.apache.commons.daemon.DaemonContext;   
  3.   
  4. public class DaemonTest implements Daemon {   
  5.   
  6.     Thread t = null;   
  7.        
  8.     @Override  
  9.     public void init(DaemonContext arg0) throws Exception {   
  10.         System.err.println("daemonTest init");   
  11.         t = new DaemonThread();   
  12.     }   
  13.   
  14.     @Override  
  15.     public void start() throws Exception {   
  16.         System.err.println("daemonTest start");   
  17.         t.start();   
  18.     }   
  19.   
  20.     @Override  
  21.     public void stop() throws Exception {   
  22.         System.err.println("daemonTest stop");   
  23.         t.interrupt();   
  24.     }   
  25.        
  26.     @Override  
  27.     public void destroy() {   
  28.         System.err.println("daemonTest destroy");   
  29.     }   
  30. }  
  1. public class DaemonThread extends Thread {   
  2.   
  3.     @Override  
  4.     public void run() {   
  5.         while( Thread.interrupted() ) {   
  6.             System.err.println("run");   
  7.             try {   
  8.                 Thread.sleep(5000);   
  9.             } catch (InterruptedException e) {   
  10.                 Thread.currentThread().interrupt();   
  11.                 return;   
  12.             }   
  13.         }   
  14.     }      
  15. }  
init에서 초기화, start에서 처리할 작업을 별도의 쓰레드로 생성해서 실행한다. start 메소드 호출후 반드시 return 되어야 데몬이 시그널 처리를 제대로 할 수 있다.
stop, destroy 는 중지 신호가 오면 차례되로 호출된다.

이제 실행/중지 스크립트를 작성한다.
Jsvc를 싱행하는데 필요한것은 실행하는 계정(user), JAVA_HOME(-home), 프로세스ID 파일(-pidfile), 출력지정(-outfile, -errfile), 클래스파일(-cp) 등이 있다.
  1. #!/bin/sh   
  2. JAVA_HOME=/usr/lib/jvm/java-6-sun   
  3. DAEMON_HOME=/home/lyb1495/commons-daemon-1.0.1/bin/jsvc-src   
  4. DAEMON_USER=lyb1495   
  5. DAEMONTEST_HOME=/home/lyb1495/workspace/Daemon   
  6. PID_FILE=$DAEMONTEST_HOME/daemon_test.pid   
  7.   
  8. CLASSPATH=\   
  9. $DAEMONTEST_HOME/bin:\   
  10. $DAEMONTEST_HOME/lib/commons-daemon.jar   
  11.   
  12. case "$1" in   
  13.   
  14.     start)   
  15.     #   
  16.     # Start Daemon   
  17.     #   
  18.     $DAEMON_HOME/jsvc \   
  19.     -user $DAEMON_USER \   
  20.     -home $JAVA_HOME \   
  21.     -wait 10 \   
  22.     -pidfile $PID_FILE \   
  23. -errfile '&1' \   
  24.     -cp $CLASSPATH \   
  25.     DaemonTest   
  26.     #   
  27.     # To get a verbose JVM   
  28.     #-verbose \   
  29.     # To get a debug of jsvc.   
  30.     #-debug \   
  31.     exit $?   
  32.     ;;   
  33.   
  34.   stop)   
  35.     #   
  36.     # Stop PostMan   
  37.     #   
  38.     $DAEMON_HOME/jsvc \   
  39.     -stop \   
  40.     -pidfile $PID_FILE \   
  41.     DaemonTest   
  42.     exit $?   
  43.     ;;   
  44. #   
  45.   *)   
  46.     echo "Usage DaemonTest.sh start/stop"  
  47.     exit 1;;   
  48. esac  
이제 Java 데몬을 실행하기 위한 모든 준비를 마쳤다.


위에서 작성한 스크립트 파일을 이용해 Java 데몬을 실핸한다.
정상적으로 데몬이 시작된다면 PID_FILE에 지정한 파일이 생성된것을 확인할 수 있다.


데몬을 중지하려면 start 대신 stop을 입력으로 스크립트를 실행하면 된다.

'Dev > JAVA' 카테고리의 다른 글

Spring framework 설치  (0) 2012.11.25
Java Simple Daemon  (0) 2011.06.05
자바 이미지 사이즈 추출 예제  (0) 2011.04.23
자바 이미지 리사이즈(썸네일)  (0) 2011.04.06

 글쓴이 : 푸우     날짜 : 08-03-01 19:09     조회 : 486    


요즘 통 글을 안 올렸네요.
요즘 회사일로 정신이 없네요.
죄송하구요. ^^; 
아무튼 이번에는 UNIX/LINUX의 Deamon 프로세스 만드는 것에 대해 정리해 보도록 하겠습니다.
 
1. Daemon이란?
 
뭐 이글을 관심이 있어서 읽고 계시는 분 중에 Daemon이 뭔지를 모르시는 분은 없겠지만...
그래도 한번 정리해 봅니다.
Daemon의 뜻 자체는 "악마", "악령", "귀신"과 같이 좀 무시무시 합니다.
하지만 Daemon의 어원은 신화에서 신과 인간사이의 초자연적인 영적존재로서의 수호신에서 나왔다고 합니다. 뭐 좋은쪽으로 생각하죠.
컴퓨터 상에서 Daemon은 겉으로는 보이지 않지만 항상 뒤에서 뭔가를 계속해서 수행해 주는 프로그램을 말합니다. 예로 httpd, ftpd, telnetd 등...
이런면에서 왜 Daemon이라는 이름 지었는지 이해가 가네요.
윈도우즈에서는 Daemon이라는 용어가 마음에 들지 않았는지 아니면 뭔가 꼭 튀게 해야한다고 생각했는지 몰라도... UNIX/LINUX의 Daemon과 같은 역할을 하는 프로그램을 Service 라고 합니다.
"데몬"은 이름에 뭔가 철학을 담아 지은것 같은데... "서비스"... 참 단순해서 좋긴 좋네요. ㅋㅋ  ^^;
 
Daemon 프로그램이 되려면 몇가지 특징을 갖추어야 하지만 가장 중요한 것은 "OS가 부팅되면 사용자의 개입없이 실행될 수 있을 것"입니다.
이 말은 다시 말해 누군가가 로그인을 하여 굳이 실행하지 않아도 OS의 init프로세스에 의해 실행될 수 있어야 한다는 이야기 이고 이럴려면 프로그램을 제어하는 터미널(tty)를 갖지 말아야 한다는 것 입니다. 반대로 말하면 누군가 로그인 해서 데몬을 시작시켰다면 로그아웃할 때 해당 데몬은 계속해서 살아 있어야 한다는 말도 됩니다.
 
이제 이러한 특징을 갖는 프로그램을 만드는 방법을 단계별로 알아보도록 하죠.
 
 
2. 로그 아웃시 프로그램 종료되지 않게 하기
 
우선 데몬은 아니더라도 데몬과 비슷하게 수행하면 계속해서 작업을 수행 할 수 있도록 하는 방법에 대해서 알아 보겠습니다.
 
기본 소스는 다음과 같습니다.
 
#include <stdio.h>

int work()
{
        FILE *fp;
        unsigned long count=0;

        fp=fopen("/tmp/daemon.out""wt");
        if(fp==NULL) {
                printf("File Open Error\n");
                return -1;
        }

        while(1){
                sleep(1);
                fprintf(fp, "%lu\n", count);
                fflush(fp);
                fprintf(stdout, "%lu\n", count++);
        }
        fclose(fp);

        return 0;
}

int main(int argc, char *argv[])
{
        work();

        return 0;
}
 
 
위의 프로그램은 간단하니깐 보시면 아시겠지만 main()함수가 수행되면 work()라는 함수를 수행하게 됩니다.
work()함수는 무한루프를 돌면서 1초마다 "/tmp/daemon.out"파일에 카운팅을 기록합니다.
또 표준출력으로도 같은 값을 출력하는 프로그램입니다.
위의 소스를 컴파일하여 daemon이라는 실행파일을 생성했다고 하고 다음의 글들을 작성토록 하겠습니다.
 
자 그럼 로그아웃이 될때 어떤 현상이 일어날지에 대해 한번 알아보도록 하죠.
 
로그아웃하거나 해당 터미널이 끊기게 되면 OS 해당 터미널을 제어단말로 사용하던 모든 프로그램에게 특별한 신호를 보내게 됩니다.
이 신호가 SIGHUP, 즉, Hangup 시그널입니다.
일반적인 프로그램은 이 Hangup 시그널을 받으면 정상종료를 하게 됩니다.
뭐 프로세스가 알아서 정상종료 한다기 보다는 이 시그널을 어떻게 처리하라는 루틴을 구현하지 않은 프로세스는 조용히 OS가 죽이는 것이죠.
 
OS에 SIGHUP을 무시하게 해주는 'nohup'이라는 쉘명령어가 있습니다.
일반적인 사용방법은 다음과 같습니다.
 
#nohup daemon&amp;amp;
 
위의 명령어 중 daemon은 데몬 프로그램의 이름이고 마지막 &는 이 글의 주제와는 상관없지만 백그라운드로 실행해서 프롬프트를 다시 얻기 위함입니다.
이렇게 daemon을 실행한 뒤 로그아웃하거나 단말기를 끊고 다시 접속한 다음 "ps -ef | grep daemon" 명령을 통해 보시면 daemon이 살아 있음을 보실 수 있으실 것 입니다.
또한 "tail -f /tmp/daemon.out" 해서 보시면 살아 있을 뿐 더러 원래의 기능도 정상적으로 수행 하고 있음을 알 수 있습니다.
 
그런데 여기서 원래 daemon은 파일 뿐만 아니라 화면에도 카운팅 번호를 출력하도록 되어 있었는데 위의 명령의 수행 후에는 아래와 같은 메시지만 남기고 나타나지 않습니다.
 
appending output to `nohup.out'<br />
 
이는 nohup 명령어가 daemon의 표준 출력을 현재 경로의 'nohup.out'이라는 파일로 리다이렉트 시켰기 때문입니다.
 
어찌되었건 쉘에서 제공하는 명령어를 통해 데몬과 유사한 기능을 하도록 해 보았네요. 
 
자 이번에는 'nohup'과 같은 기능을 시스템 함수로 구현해 보도록 하겠습니다.
 
골자는 프로그램 내에서 SIGHUP시그널을 무시할 수 있도록 코딩하는 것입니다.
 
 위 함수에 #include <signal.h> 를 포함하고 main함수를 다음과 같이 고칩니다.
 
 
int main(int argc, char *argv[])
{
        signal(SIGHUP, SIG_IGN);

        work();

        return 0;
}
 
 
지금 부터는 work()함수의 표준 출력이 귀찮아 지므로 표준 출력으로 내보는 문장은 적절히 삭제하셔도 좋습니다.  
위의 main()함수는 signal()함수를 통해 SIGHUP시그널을 무시하도록 설정 한 뒤 work()함수를 수행한 것입니다.
 
컴파일 후 테스트는 여러분의 몫으로 하구요.
 
SIGHUP을 무시하는 방법은 아니지만 또 다른 방법이 있는데 이는 프로세스 내에서 자신의 그룹아이디를 바꾸는 것입니다.
 
이는 로그 아웃시 현재 터미널을 제어 단말기로 하고 있는 프로세스에 OS가 SIGHUP시그널을 보낼 때 쉘프로세스의 아이디를 그룹아이디로 갖는 모든 프로세스에게 보낸다는 것에 착안한 것입니다.
 
즉, 프로그램은 특정 쉘프로세스에서 수행되기 때문에 일반적으로 프로세스 그룹아이디는 수행 환경이 되었던 쉘프로세스 아이디를 갖게 되는데 이를 프로세스 내에게 바꾸는 것입니다. 
 
int main(int argc, char *argv[])
{
        int newpgid;

        newpgid = setpgrp();

        work();

        return 0;
}
 
위의 소스에 보이는 setpgrp()함수는 자신의 프로세스 그룹을 자신의 프로세스아이디로 바꿔줍니다.
이렇게 하면 로그아웃시 이 프로세스는 아예 SIGHUP시그널을 받지도 않으므로 종료되지 않습니다.
 
자 여기까지는 데몬 프로그램을 만드는 법이라기 보다는 일반적으로 프로세스에서 일어나는 일과 이들을 처리하는 방법, 그리고 간단히 데몬과 유사한 효과 내기라고 생각하시면 될 듯 싶습니다.
 
 
3. fork에 의한 Daemon만들기
 
 
위에서 이야기 한 방법들도 뭐 잘못된 방법들은 아니지만 일반적으로는 이제부터 이야기 하는 방법으로 주로 데몬을 만듭니다.
main()함수를 다음과 같이 바꾸세요.
 
int main(int argc, char *argv[])
{
        int pid;

        pid=fork();
        switch(pid){
        case -1:
                fprintf(stderr, "Fork Error\n");
                break;
        case 0:         // child
                break;
        default:        // parent
                return 0;
        }

        work();

        return 0;
}
 
위의 main()함수는 프로그램이 시작되자 마자 fork()를 수행해서 자식프로세스는 work()함수를 수행하고 부모프로세스는 종료하게 합니다.
그러면 사실 자식프로세스는 아직 살아 있는데 부모프로세스가 터미널과 연결되어 있었는데 사라지게 됩니다. 고로 자식 프로세스는 제어단말기를 가지지 않게 되고 부모가 없으므로 고아프로세스가 되었네요.
이렇게 고아프로세스가 발생하면 OS는 이 고아 프로세스를 init프로세스의 자식으로 만들어 줍니다.
부모,자식,고아를 이야기 했으니 입양이라고 해야 할까요? ㅋㅋㅋ
하지만 원래 init프로세스는 1번 프로세스로서 조상 프로세스에 해당됨으로 입양이라고 하기는 좀 그렇네요.
 
아무튼 위의 프로그램은 아무 문제가 없습니다. 좀비가 발생하지도 않구요.
 
하지만 이런 케이스를 생각해 보죠.
daemon도 프로세스이므로 현재 작업디렉토리를 갖습니다.
그래서 이 daemon이 실행된 후 daemon을 실행 시켰던 디렉토리가 속한 파일시스템을 "umount" 시키려 한다면 OS는 해당 파일시스템이 사용되고 있다고 umount 하지 못한다고 할 것 입니다.
이런 경우 해당 데몬을 내려야 하는데...
더욱 나쁜 경우는 어떤 데몬이 이 파일시스템을 사용하고 있는지를 알기가 힘들다는 것이죠.
그래서 데몬은 데몬이 되기 전에 현재 경로를 "/'와 같이 "umount"될 수 없는 곳으로 옮기는 것이 좋습니다.
 
또 한가지 고려해야 할 것은 현재 daemon은 뭐 파일에 숫자만 적고 있지만 여러분이 만드는 deamon은 어떤 일을 하게 될 지 사실 모릅니다.
예를 들어 daemon이 또 fork를 해서 자식 프로세스들을 갖을 수도 있고 exec()함수나 system()함수에 의해 아예 다른 프로그램을 실행 시킬 수도 있을 것입니다.
이때 새로 생성되는 프로세스를 현재 daemon이 제어 할 수 없다면 이 또한 문제일 수 있겠죠?
그래서 데몬프로세스는 데몬이 된 직 후 자신이 속한 프로세스 그룹의 리더가 아니라면 새로운 프로세스 세션을 만들고 자신이 리더가 된 후 다음 작업들을 하게 됩니다.  이러한 기능을 하는 함수가 바로 setsid()라는 함수 입니다. (참조: http://teamblog.joinc.co.kr/yundream/226)
 아래 소스는 chdir()과 setsid()함수를 호출하여 위에서 이야기한 내용을 반영하고 있습니다.
 
int main(int argc, char *argv[])
{
        int pid;

        pid=fork();
        switch(pid){
        case -1:
                fprintf(stderr, "Fork Error\n");
                break;
        case 0:         // child
                break;
        default:        // parent
                return 0;
        }

        chdir("/");
        setsid();

        work();

        return 0;
}
 
 
자 여기까지 하면 뭐 데몬이 잘 만들어 진 것 입니다.
 
추가로 실제 데몬을 프로그래밍 하실 때 주의하실 점은 시그널에 대한 처리를 꼭 하시라는 것 입니다.
위의 샘플 소스는 뭐 특별하게 시그널 처리를 할께 딱히 없지만 예를 들어 웹서버와 같이 통신 프로그램인 경우 SIG_PIPE와 같은 시그널을 처리해야 합니다.
 
 
4. 오뚜기 같은 Daemon만들기
 
마지막으로 이야기 하는 것은 일반적인 데몬에 대한 이야기는 아니구요 팁같은 거라고 할까요?
데몬은 서비스 제공하는 프로세스이다 보니깐...
시스템이 시작되면 시작되서 끝날때 까지 살아 있어야 하는데...
우리가 짜는 프로그램이 문제가 없다고 장담할 수는 없겠죠? (저만 그런가?)
 
만약 데몬으로 띄운 프로그램이 죽으면 타격이 크죠.
뭐 그 타격은 타격이더라도 세션이나 트랜잭션이 중요한 서비스가 아닌 경우라면 빨리 다시 시작이라도 시켜서 정상화를 시키고 싶은 경우가 있습니다.
 
이런 경우에 다음과 같은 방법으로 할 수 있을 것입니다.
먼저 일반 데몬을 하나 만들기 위해 일반 fork하시구요.
그리고 다시 fork를 해서 자식프로세스는 서비스를 수행하구요 부모프로세스는 자식이 종료되기를 기다립니다.
그런데 자식프로세스는 무한루프일 거니깐...
부모프로세스 입장에서 자식이 종료되었다면 실제로는 뭔가 문제가 생긴 것이겠죠?
이때 다시 fork를 해서 위의 과정을 반복합니다.
 
소스는 다음과 같습니다.  
 
int main(int argc, char *argv[])
{
        int pid;
        int ret;

        if (( pid = fork()) < 0) {
                fprintf(stderr, "Main Fork Error\n");
                return 0;
        } else if(pid > 0) {
                return 0;
        }

        chdir("/");
        setsid();

        while(1) {
                if (( pid = fork()) < 0) {
                        fprintf(stderr, "Sub Fork Error\n");
                        return 0;
                } else if(pid == 0) {
                        break;
                } else if(pid > 0) {
                        wait(&ret);
                }
        }

        work();

        return 0;
}
 
 
만약 자식이 종료될때 상태를 알고자 한다면 wait()함수의 인자인 ret값을 조사하면 됩니다.
 
자 이렇게 해서 UNIX/LINUX에서 Daemon만들기에 대한 이야기를 마치도록 하겠습니다. 


출처 : http://honeybox.tistory.com/

1) 데몬의 종류

데몬이란 시스템에 백그라운드 모드로 수행중이며 어떤 사건, 즉 이벤트를 기다리거나 주기적으로 주어진 작업을 수행하기 위하여 대기하고 있는 프로세스를 의미한다. 일반적으로 데몬프로세스는 이름끝에 'd'자가 붙는다.
기본적으로 리눅스에는 여러 기능과 서비스를 제공하기 위한 다양한 데몬 프로세스들이 시스템에서 돌아가고 있다.
이런 서비스 데몬들의 실행여부는 레드햇 리눅스 계열에서 ntsysv 커맨드로 조정하면 된다. 리눅스상에서 현재 실행되고 있는 데몬의 현황을 보려면 pstree 커맨드를 쓴다.

데몬의 실행방식은 크게 stand-alone방식과 xinetd(슈퍼데몬)방식이 있다.
 # Stand-alone방식
(말뚝보초처럼 항상실행대기)
이 방식의 데몬들은 데몬이 시작되면 말 그대로 자기 스스로 시스템에서 상주하며 클라이언트 요청에 응답을 보내주는 방식으로 보통 아파치 데몬처럼 클라이언트의 요청이 잦은 데몬들이 이런 방식으로 실행된다. 스탠드 얼론방식의 데몬을 확인하려면 쉘상에서 pstree 명령을 내리면 데몬들을 트리형식으로 보여준다. 스탠드 얼론 방식의 데몬들은 xinetd방식보다는 클라이언트 요청에 신속하게 대응한다는 장점은 있으나 이런 스탠드 얼론 데몬들이 시스템에서 많이 생성되게되면 시스템의 자원낭비가 심해지게 되고 퍼포먼스도 떨어지게 된다.

 # inetd방식
(클라이언트 요청이 있을때만 실행)
스탠트 얼론처럼 자기 스스로 독립적으로 시스템에 실행되는게아니라 xinetd라는 수퍼데몬이 시스템에서 대기하고 있다고 클라이언트 요청이 들어오면 xinetd데몬에 의해 해당 서비스를 제공해줄 데몬을 실행시키는 방식이다. telnet이나 ftp같이 비교적 클라이언트 요청의 빈도가 낮은 서비스들은 이런 xinetd데몬이 시스템 활용측면에서는 유리하다. 또한 tcp wrapper를 써서 보안을 손쉽게 설정할 수 있는 것도 장점이다. 그러나 전술한 아파치 데몬같이 클라이언트의 자잘한 요청이 많은 서비스에 대해서는 inetd방식이 시스템효율을 도리어 떨어드리게된다. xinetd데몬은 스탠드 얼론방식으로 실행되는 슈퍼데몬이며 서비스 요청시 xinetd데몬의 차일드 프로세스로 다른 데몬이 실행된다. 이를 확인하려면 pstree로 xinetd데몬을 확인하고 다른 한텀창에서 telnet이나 ftp로 자신의 호스트에 접속해보라. 그럼 xinetd데몬에서 차일드 프로세스로 해당 데몬이 실행되는 것을 확인할 수 있다.

 

 

2) /etc/rc.d/init.d/ 데몬 설명

/etc/rc.d/init.d/autofs
오토마운트 파일시스템(Automount Filesystem) 데몬 스크립트입니다. 파일시스템 사용을 요구받았을 경우에는 마운트를 하고 파일시스템 사용이 끝났을 경우에는 마운트를 해제하게 됩니다.

/etc/rc.d/init.d/crond
cron 데몬 스크립트입니다. 여러분들께서도 잘 아시는 바와 같이 cron은 특정한 시간에 지정된 작업을 주기적으로 하도록 하는 리눅스 작업관리자 데몬입니다. 이런 cron데몬을 시작, 재시작 또는 종료시키는 스크립트입니다.

/etc/rc.d/init.d/functions
리눅스 시스템의 /etc/rc.d/init.d/디렉토리내의 거의 모든 쉘 스크립트에서 사용되어지는 함수를 내장하고 있는 파일입니다.

/etc/rc.d/init.d/gpm
GPM은 Midnight Commander와 같은 텍스트기반의 리눅스 어플리케이션에서 마우스의 복사 및 붙이기 기능과 콘솔상에서의 마우스 팝업기능을 제공하기 위한 데몬입니다.

/etc/rc.d/init.d/halt
halt는 시스템이 런레벨(runlevel) 0또는 런레벨(runlevel)6로 실행이 될 때에 init 프로세스에 의해 실행되는 스크립트로서 현재 시스템에 실행된 모든 프로세스를 죽이고 모든 파일시스템의 마운트를 해제한 후에 시스템을 종료(halt)시키거나 재부팅(reboot)합니다.

/etc/rc.d/init.d/iptables
iptables는 /etc/sysconfig/iptables에 미리 정의된 룰에 따라서 리눅스 서버의 방화벽을 실행 및 중지하기 위한 스크립트입니다. 즉, iptables로 구현하는 패킷필터링(packet filtering)방화벽입니다.

/etc/rc.d/init.d/irda
IrDA (Infrared Data Association)데몬 스크립트로서 IrDA는 무선통신, 적외선 통신을 위한 산업표준입니다. IrDA는 최근 거의 모든 장치들(laptops, LAN아답터, PDA, 프린터, 휴대폰등)에 사용될 수 있으며 9600bps에서 4Mbps의 속도범위를 가집니다.

/etc/rc.d/init.d/isdn
isdn 서비스를 시작하거나 종료하는 스크립트입니다.

/etc/rc.d/init.d/kdcrotate
/etc/krb5.conf에 정의되어 있는 KDC 리스트를 회전시키는 스크립트입니다.

/etc/rc.d/init.d/killall
현재 실행중인 서비스들을 대상으로 모두 중지시키는 스크립트입니다. 따라서 이 스크립트는 주로 시스템을 중지하거나 재시작할 때에 실행되는 스크립트입니다.

/etc/rc.d/init.d/kudzu
kudzu데몬은 새로운 하드웨어나 또는 변경된 하드웨어를 조사하여 설정하는 데몬입니다. 또한 kudzu데몬은 현재의 하드웨어 정보와 /etc/sysconfig/hwconf에 저장해 하드웨어 정보를 비교하여 변경된 하드웨어 또는 해로운 하드웨어가 존재하는가를 알아냅니다.
즉, 시스템 하드웨어의 변경 또는 새로운 하드웨어의 추가장착등과 같은 하드웨어에 대해 조사하는 kudzu데몬을 시작시키거나 종료하는 스크립트입니다.

/etc/rc.d/init.d/netfs
Network Filesystem(NFS)와 SMB(Lan Manager/Windows ), NCP(NetWare)를 마운트 시키거나 마운트 해제하는 데몬 스크립트입니다.

/etc/rc.d/init.d/network
리눅스 서버의 통신을 가능하도록 하기 위하여 관련 파일에 설정되어 있는대로 네트워크 설정을 하거나 중단하는 스크립트입니다.

/etc/rc.d/init.d/nfs
NFS 서비스 데몬을 시작(종료, 재시작)하는 스크립트입니다. NFS는 TCP/IP 네트워크상에서 파일공유를 위해 많이 사용되고있는 프로토콜입니다. 이 스크립트로 NFS서비스를 실행하면 /etc/exports파일의 설정대로 NFS서버기능을 할 수 있도록 설정합니다.

/etc/rc.d/init.d/nfslock
NFS파일 락킹서비스를 시작(종료,재시작)하는 스크립트입니다.

/etc/rc.d/init.d/nscd
네임서비스 캐쉬데몬(Name Service cache Daemon)을 시작하는 스크립트입니다. NSCD데몬은 가장일반적인 네임서비스에 대한 캐쉬기능을 제공하는 데몬으로서 /etc/passwd, /etc/group, /etc/hosts파일등에 대한 캐쉬정보를 가지고 있습니다. NSCD데몬의 설정파일은 /etc/nscd.conf입니다.

/etc/rc.d/init.d/pcmcia
pcmcia 데몬을 시작(종료)하기 위한 스크립트입니다. PCMCIA는 일반적으로 노트북등에서 사용되는 장치(모뎀, 이더넷등)를 지원하기 위한 것입니다.

/etc/rc.d/init.d/portmap
RPM 포트맵퍼(portmap daemon)을 시작(종료)하는 스크립트입니다. 일명 포터맵퍼(portmapper)라고 합니다. 이 portmapper는 NFS와 NIS 등과 같은 프로토콜이 사용되는 RPC연결을 제어하는 역할을 합니다. 따라서 이 portmapper는 RPC매카니즘을 사용하는 프로토콜이 탑재되어있어 서버로 사용되는 시스템에서는 반드시 실행되어있어야 합니다.

/etc/rc.d/init.d/random
리눅스 시스템에서의 난수사용을 위하여 난수발생데몬인 random을 시작시킵니다.

/etc/rc.d/init.d/rawdevices
하드드라이브 파티션과 같은 블록장치에 rawdevice를 할당하는 스크립트입니다. 잘아시는 Oracle과 같은 어플리케이션에서 사용될 수 있습니다. /etc/sysconfig/rawdevices파일을 수정, 편집함으로써 rawdevice에 블록장치매핑과 할당을 할 수 있습니다.

/etc/rc.d/init.d/single
시스템 실행레벨(runlevel) 1로 가고자 할 때 사용하는 스크립트입니다. 이 스크립트가 실행되면 시스템의 모든 프로세스들을 죽인 다음 시스템을 실행레벨 1상태로 만들어 줍니다. 실행레벨 1상태는 관리자(root) 전용모드입니다.

/etc/rc.d/init.d/sshd
sshd라는 OpenSSH서버데몬을 실행(중지)하는 스크립트입니다. telnet과는 달리 ssh는 암호화하여 통신을 하기 때문에 보안을 위한 통신방법으로 주로 사용됩니다. Telnet처럼 원격서버 로그인을 하는 ssh를 사용하려면 sshd데몬이 실행되어 있어야합니다. 이 스크립트는 sshd데몬을 실행시켜주는 스크립트입니다. 참고로 ssh는 TCP 22번과 UDP 22번을 사용합니다.

/etc/rc.d/init.d/syslog
syslog는 리눅스 시스템의 필수적인 로깅시스템입니다. 이런 로깅시스템을 시작(종료)하는 스크립트입니다. 이 스크립트에 의해 로깅시스템의 데몬인 syslogd가 실행되면 /etc/syslog.conf파일을 참조하여 각 설정에 해당하는 조건이 되면 지정된 로그파일에 로그메시지를 기록합니다. 로그파일이 기록되는 디렉토리는 /var/log/이며 대표적인 로그파일로는 /var/log/messages, /var/log/secure, 그리고 /var/log/maillog등이 있습니다. 이 스크립트에 의해 실행되는 데몬은 /sbin/syslogd와 /sbin/klogd가 있습니다.
/sbin/syslogd는 로깅시스템의 주된 그리고 일반적인 로그메시지를 기록하는 주데몬이며 klogd는 커널메시지를 기록하는 커널로그데몬입니다. 그리고 서버의 로그메시지를 원격서버에 실시간으로 저장하고자 한다면 syslogd데몬 실행시에 -r옵션을 사용하여 실행하시기 바랍니다. 참고로 syslogd는 UDP 514번을 사용합니다.

/etc/rc.d/init.d/xinetd
리눅스 서버의 인터넷 수퍼데몬인 XINETD데몬을 실행시키거나 중지시키는 데몬입니다. Xinetd는 TCP_Wrapper와 함께 사용되며 대부분의 인터넷 서비스들을 관장하며 telnet이나 ftp등과 같은 특정 서비스요청을 사용자프로세스와 서비스데몬을 연결시켜주는 역할을 합니다.

/etc/rc.d/init.d/ypbind
NIS/YP 클라이언트 시스템에서 실행되는 데몬으로서 NIS 도메인(domain)에 바인드시키는 역할을 합니다. NIS클라이언트에서 수행되기 위하여 반드시 glibc 기반 시스템에서 실행되어야합니다. 하지만 NIS를 사용하지 않는 시스템에서 실행되어져서는 안됩니다.


'OS > LINUX' 카테고리의 다른 글

Linux서버에 Memcached 설치/실행 하기  (0) 2011.06.09
리눅스의 런레벨(Run level)  (0) 2011.06.09
[/etc/rc.d/init.d/*] 데몬 실행 스크립트의 이해  (0) 2011.06.09
/dev/null 다시 만들기  (0) 2011.06.04
/dev/zero와 /dev/null  (0) 2011.06.04

1. 심볼릭링크

 

윈도우XP에서 한글2005를 실행시킬때의 구조를 살펴보자.

설치시 특별히 디렉토리를 변경하지 않았다면, 실행파일은 다음의 위치에 있다.

 

    C:\HNC\Hwp65\hwp.exe

 

그러나, 우리는 탐색기를 열어서.. C:\HNC\Hwp65\hwp.exe 파일을 더블클릭해서 직접 실행하지는 않는다.

보통은, '시작>프로그램>한글과컴퓨터>한글2005>한글 2005' 를 실행하거나,

아니면, 바탕화면의 단축아이콘을 더블클릭한다.

 

단.축.아.이.콘...!!

윈XP에서의 단축아이콘이 리눅스에서의 심볼릭링크이다.

 

 

2. /etc/rc.d/init.d/* 파일들의 이해

 

MS윈도우즈에서 프로그램을 설치하면 대부분 'C:\Program Files' 안에 설치된다.

물론, 다른 디렉토리에 설치해도 된다.

 

리눅스도 각각의 프로그램들(데몬들)을 원하는 디렉토리에 설치할 수 있다.

rpm으로 설치한다면, 특정 디렉토리가 지정되어 있겠지만...

소스로 설치할 때는 원하는 디렉토리에 설치한다.

apache를 소스설치할 때, --prefix 옵션으로 설치 디렉토리를 지정할 수 있는 것처럼 말이다.

물론, 관습적으로 대부분 /usr/local/ 밑에 설치하는 경향이 많다.

 

이렇게 각각의 디렉토리에 설치된 각각의 데몬들을 실행하거나, 중지하는 등의 관리를 할 때는 상당히 불편하다.

각 데몬이 어디에 설치되어 있는지 모두 알아야 하기 때문이다.

 

생각해보자.

어느누가 네임서버 데몬을 실행시키는데...

 

    # /usr/sbin/named

 

와 같이 데몬의 실행파일을 직접 실행시키겠는가..??

 

보통은...

 

    # /etc/rc.d/init.d/named start

 

와 같이 실행시킨다...

 

그렇다. 각 데몬의 실행파일들이 어디에 있는지와 상.관.없.이,

관리의 편의를 위하여....

각 데몬들을 실행할 수 있게 만든 쉘스크립트 파일모아놓고 관리를 한다.

그 디렉토리가 /etc/rc.d/init.d/ 디렉토리이며,

/etc/rc.d/init.d/ 밑의 모든 파일들은 vi 편집기로도 열리는, 쉘스크립트 파일들이다.

 

마치, 윈XP에서 각 프로그램들을 하드에 설치하고..

실행할 때는 '시작>프로그램>....' 에서 실행하는 것과 비슷하다.

 

 

3. 런레벨의 이해

 

기본적으로 다음 두 가지는 알고 있다고 가정하자.

 

① 런레벨 종류

    - 런레벨 1 : 싱글모드 부팅. MS윈도우즈의 안전모드와 비슷

    - 런레벨 3 : 콘솔모드로 부팅

    - 런레벨 5 : X 윈도우로 부팅

    - 런레벨 6 : 계속 재부팅만 한다.

 

② 런레벨 수정

    - /etc/inittab 파일에서 다음 항목의 숫자를 직접 수정함으로 변경 가능

      id:3:initdefault:

 

이제, 윈XP의 '시작>프로그램>시작프로그램' 을 생각해 보자.

시작프로그램에 특정 프로그램을(프로그램의 단축아이콘을) 등록해 놓으면,

컴퓨터를 켤 때 그 프로그램이 자동으로 실행된다.

 

리눅스도 시작할 때 자동으로 실행될 프로그램(=데몬)을 등록할 수 있다.

윈XP에서는 '시작프로그램'에 등록하지만, 리눅스는 디렉토리에 심볼릭링크를 만들어서 등록한다.

 

    - /etc/rc.d/init.d/rc3.d   : 런레벨 3으로 부팅될 때 자동실행할 데몬을 등록하는 곳

    - /etc/rc.d/init.d/rc5.d   : 런레벨 5로 부팅될 때 자동실행할 데몬을 등록하는 곳

 

필자는 런레벨 3으로 부팅하며, 다음과 같은 심볼릭링크 파일들을 볼 수 있다.

 

    # cd /etc/rc.d/rc3.d/
    # ls -al
    drwxr-xr-x    2 root     root         4096 12월 15 10:32 ./
    drwxrwxr-x   10 root     root         4096 12월 15 19:02 ../
    lrwxrwxrwx    1 root     root           13 12월 15 19:01 K15gpm -> ../init.d/gpm*
    lrwxrwxrwx    1 root     root           20 12월 15 19:02 K44rawdevices -> ../init.d/rawdevices*
    lrwxrwxrwx    1 root     root           18 12월 15 19:02 K45arpwatch -> ../init.d/arpwatch*
    lrwxrwxrwx    1 root     root           15 12월 15 19:02 K75netfs -> ../init.d/netfs*
    lrwxrwxrwx    1 root     root           15 12월 15 10:30 K95kudzu -> ../init.d/kudzu*
    lrwxrwxrwx    1 root     root           17 12월 15 19:02 S10network -> ../init.d/network*
    lrwxrwxrwx    1 root     root           16 12월 15 19:01 S12syslog -> ../init.d/syslog*
    lrwxrwxrwx    1 root     root           18 12월 15 19:00 S17keytable -> ../init.d/keytable*
    lrwxrwxrwx    1 root     root           16 12월 15 19:02 S20random -> ../init.d/random*
    lrwxrwxrwx    1 root     root           17 12월 15 19:02 S29sysstat -> ../init.d/sysstat*
    lrwxrwxrwx    1 root     root           15 12월 15 10:32 S55named -> ../init.d/named*
    lrwxrwxrwx    1 root     root           16 12월 15 19:02 S56xinetd -> ../init.d/xinetd*
    lrwxrwxrwx    1 root     root           15 12월 15 19:02 S90crond -> ../init.d/crond*
    lrwxrwxrwx    1 root     root           11 12월 15 19:02 S99local -> ../rc.local*
    lrwxrwxrwx    1 root     root           23 12월 15 19:02 S99oops-firewall ->
../init.d/oops-firewall*

 

디렉토리 안을 살펴보니, 모두 심볼릭링크 파일이라는 것을 알 수 있다.

심볼릭링크 파일은 제일 앞의 퍼미션을 나타내는 부분이 'l' 로 시작되며,

어떤 파일을 심볼릭링크했는지 화살표로 표시해 준다.

 

살펴보면, 모든 심볼릭링크의 원본파일들이 상위 디렉토리(../)의 init.d 디렉토리 내의 파일들,

, /etc/rc.d/init.d/파일들 이라는 것을 볼 수 있다.

따라서, 각 데몬의 실행파일을 관리하는 스크립트 파일들을 심볼릭링크한 것이다.

 

/etc/rc.d/rc3.d/ 밑의 파일들의 파일명을 살펴보면 다음과 같은 형식이다.

 

  S[혹은 K]{숫자}{데몬파일명}

 

S 로 시작되는 링크파일은 부팅할 때 시작(Start)되는 스크립트파일이다.

K 로 시작되는 링크파일은 부팅할 때 시작되지 않는(Kill) 스크립트파일이다.

 

{숫자}는 실행되는 우선순위를 나타낸다.

crond 데몬보다, named 데몬이 중요하고 꼭 실행되어야 한다면... crond 링크보다 숫자를 낮은 숫자로 하면 된다.

예전에는 컴퓨터(서버)의 사양이 좋지 않아, '어떻해도 가장 중요한 데몬'을 실행시키기 위해서 있었지만..

지금은 별 의미가 없다..

실행되지 않을 정도의 하드웨어 사양을 찾기가 힘들다... ^^;

{숫자}는 같은 숫자로 중복해서 사용할 수도 있다.

 

ntsysv 명령어로 각 데몬을 체크하거나, 체크를 지우는 것도...

알고보면 S 를 K 로 바꾸거나, K 를 S 로 바꾸는 작업이다.

 

/etc/rc.d/rc3.d/ 디렉토리에서는 S로 시작해서 심볼릭링크가 되어 있고,

/etc/rc.d/rc5.d/ 디렉토리에서는 K로 시작해서 심볼릭링크가 되어 있다면...

같은 /etc/rc.d/init.d/ 밑의 같은 데몬스크립트 파일이라고 하더라도..

런레벨마다 실행되거나, 실행되지 않을 수 있다.


출처 :
http://cafe.naver.com/asii/857

'OS > LINUX' 카테고리의 다른 글

리눅스의 런레벨(Run level)  (0) 2011.06.09
데몬의 종류, /etc/rc.d/init.d/  (0) 2011.06.09
/dev/null 다시 만들기  (0) 2011.06.04
/dev/zero와 /dev/null  (0) 2011.06.04
Perl 입문  (0) 2011.05.17

Java Simple Daemon

뭐에 쓰는 물건인고?

Java Simple Daemon은 자바를 이용해서 데몬 프로그램을 작성하도록 도와주는 프레임워크이다(비록 프레임워크라고 부르기엔 너무도 작지만.. ^^).
가끔씩 특정 디렉토리에 들어오는 파일을 감시해서 파일이 들어오면 그 파일을 DB에 넣기만 하거나, 혹은 어떤 방식으로든 메시지를 받아서 받은 메시지를 가공해 다른 쪽에 메시지로 넘겨 주거나 하는 등의 역할을 하는 그런 프로그램을 자바로 짤 경우가 있다.
이러한 프로그램들은 일반적으로 그래픽 사용자 인터페이스(GUI)나 화면 출력이 필요 없이 파일로 로그만 남기고 자기 할 작업을 한다. 이러한 프로그램을 데몬(Daemon)이라 부른다.
자바로 이러한 데몬을 작성할 경우, 데몬을 실행시키는 것은 문제가 없다.

$ nohup java some.Daemon &
이러한 식으로 실행하면 된다. 헌데 문제는 종료이다. 프로그램과 의사 소통할 무슨 방법이 없기 때문에 Unix에서 ps -ef명령으로 "java" 프로세스를 찾아서 kill명령을 내리거나 윈도우의 경우에는 프로세스 종료를 시킬 수 밖에 없다. 이러한 문제를 해결하기 위해 만든 것이 Java Simple Daemon(이하 JSD)이다.

프로젝트 홈

다운로드

Java Simple Daemon 다운로드 목록

어찌 작동하는고?

원리는 단순하다. 데몬 역할을 하는 자바 클래스를 실행시켜주면서 쓰레드가 하나 떠서 사용자의 홈 디렉토리(Unix에서 $HOME 환경변수가 가리키는 디렉토리)에 특별한 파일이 존재하는지를 검사한다. 만약 그 특별한 파일이 존재한다면 JVM을 자동으로 종료시켜준다. JSD는 그 특별한 파일이 있는지 검사하는 역할과, 그 파일을 생성 시켜주는 역할을 한다.

덤으로, JSD는 데몬 클래스에 따라 락(Lock) 파일도 생성해준다. 홈 디렉토리에 락 파일이 존재할 경우, 데몬을 다시 띄우려고 하면 데몬 띄우기를 거부한다.

사용하기

  • 데몬 클래스는 net.kldp.jsd.SimpleDaemon 인터페이스를 구현해야 한다.
    • public void startDaemon() : 데몬작업을 수행하는 메소드. 여기에 실제 작업 구현이 들어간다.
    • public void shutdown() : 데몬이 종료하기 전에 수행할 작업을 기록한다.
  • net.kldp.jsd.SimpleDaemonManager의 객체를 생성하고, 객체에 데몬 클래스를 등록해 준다.
  • net.kldp.jsd.SimpleDaemonManager.start()를 실행하면 데몬이 시작된다.
  • net.kldp.jsd.SimpleDaemonManager.shutdownDaemon()를 실행하면 데몬을 종료시키는 파일이 $HOME 디렉토리에 생성되어, 데몬을 종료시키게 된다.

예제 보기

아래 예제는 대책없이 화면에 시간을 출력하는 데몬이다.

  • 데몬의 시작 : java net.kldp.jsd.sample.ShowTime
  • 데몬의 종료(다른 콘솔 창에서) : java net.kldp.jsd.sample.ShowTime -shutdown
여기서 데몬을 종료하기 전에 다시 한번 데몬을 시작해보면 락 파일이 존재하기 때문에 실행을 거부하는 것을 볼 수 있다.
/*
 * Created on 2004. 11. 6.

 */
package net.kldp.jsd.sample;

import java.io.IOException;
import java.util.Date;

import net.kldp.jsd.IllegalSimpleDaemonClassException;
import net.kldp.jsd.SimpleDaemon;
import net.kldp.jsd.SimpleDaemonManager;

/**
 * SampleDaemon 예제.
 * 
 * 현재 시간을 계속해서 보여주는 데몬이다.
 * 
 */
public class ShowTime implements SimpleDaemon {

  public static void main(String args[]) {
    // -shutdown 옵션이 있을 경우 데몬을 종료시킨다.
    if (args.length > 0 && args[0].equals("-shutdown")) {
      System.out.println("ShowTime 종료시작.");
      
      try {

        SimpleDaemonManager sdm = SimpleDaemonManager.getInstance(ShowTime.class);
        sdm.shutdownDaemon();
      } catch (IOException e1) {
        e1.printStackTrace();
      } catch (IllegalSimpleDaemonClassException e) {
        e.printStackTrace();
      }
      return; // 프로그램 종료.
    }

    SimpleDaemonManager sdm = null;
    
    try {
      sdm = SimpleDaemonManager.getInstance(ShowTime.class);
      sdm.start();
    }  catch (Exception e) {
      e.printStackTrace();
    }
  }
  
  /**
   * 데몬 작업수행 : 현재 시간을 계속 보여준다.
   */
  public void startDaemon() {
    while (true) {
      Date now = new Date();
      System.out.println(now.toString());
      try {
        Thread.sleep(5000);
      } catch (Exception ex) {
        ex.printStackTrace();
      }
    }
    
  }

  /**
   * ShowTime 종료시 실행할 내용들. 
   */
  public void shutdown() {
    System.out.println("ShowTime을 종료합니다.");
  }
}

[출처] Java Simple Daemon|작성자 승빈파파


'Dev > JAVA' 카테고리의 다른 글

Spring framework 설치  (0) 2012.11.25
자바 데몬(daemon) 만들기  (0) 2011.06.09
자바 이미지 사이즈 추출 예제  (0) 2011.04.23
자바 이미지 리사이즈(썸네일)  (0) 2011.04.06

+ Recent posts