OS는 CentOS,

 

리눅스에서 쉽게 데몬 프로세스를 만들기 위해서는 'nohup' 명령어를 사용할 수 있다.

하지만 프로세스를 종료 시킬 때, 따라오는 번거로운 작업 등이 있다. 물론 nohup을 사용해도 된다.(실제 파일 체크 기법을 사용 중)

무튼 Java는 UNIX의 시그널 처리를 할 수 없기 때문에, 중지 신호(TERM signal)를 처리하기 위해서는 따로 구현을 해야 한다.

이러한 번거로움을 해결하기 위해 자카르타의 하위 프로젝트 중의 'Commons daemon'을 이용한다. Commons daemon은 중지 신호를 받으면 미리 지정된 메소드를 실행한다.

 

1. JSVC 설치하기

commons-daemon-1.1.0.jar
다운로드
commons-daemon-1.1.0-src.tar.gz
다운로드

# commons-daemon을 설치할 디렉토리 생성, 사용자마다 편한 위치에 생성하면 된다.
> mkdir /root/commons-daemon
> cd /root/commons-daemon

# wget 명령어를 사용하여 필요 패키지 및 .jar파일 다운로드
> wget http://www.apache.org/dist/commons/daemon/binaries/commons-daemon-1.1.0.jar
> wget http://www.apache.org/dist/commons/daemon/source/commons-daemon-1.1.0-src.tar.gz
# ※ 만약 다운로드가 안된다면 경로가 바뀌었을 가능성이 크기 때문에 http://www.apache.org/dist/commons/daemon 로 들어가서 경로를 재탐색한다.

# 다운받은 파일을 압축 해제한다.
> tar zxvf commons-daemon-1.1.0-src.tar.gz

# 폴더 이동 후 configure 및 make를 실행한다.
> cd commons-daemon-1.1.0-src/src/native/unix
> ./configure
> make

# 생성된 JSVC 파일을 작업할 폴더로 이동한다.
> mv jsvc /root/commons-daemon

 

2. 실행할 Java 클래스 생성

JSVC에 의해 실행되는 Java 클래스는 Daemon 인터페이스를 구현해야 한다. 또한, 스레드로 실행되어야 하므로 Runnable도 구현해야 한다.

※ 만약 스레드로 구동하지 않을 경우, 종료처리가 제대로 되지 않으며 "Service exit with a return value of 143" 라는 오류를 표시할 것이다.

 

테스트 프로그램은 1초마다 숫자를 하나씩 증가시키면서 찍는 프로그램

File name : TestDaemon.java

import org.apache.commons.daemon.Daemon;
import org.apache.commons.daemon.DaemonContext;
import org.apache.commons.daemon.DaemonInitException;
 
public class TestDaemon implements Daemon, Runnable {
    private String status = "";
    private int no = 0;
    private Thread thread = null;
 
    @Override
    public void init(DaemonContext context) throws DaemonInitException, Exception {
        System.out.println("init...");
        String[] args = context.getArguments();
        if(args != null) {
            for(String arg : args) {
                System.out.println(arg);
            }
        }
        status = "INITED";
        this.thread = new Thread(this);
        System.out.println("init OK.");
        System.out.println();
    }
 
    @Override
    public void start() {
        System.out.println("status: " + status);
        System.out.println("start...");
        status = "STARTED";
        this.thread.start();
        System.out.println("start OK.");
        System.out.println();
    }
 
    @Override
    public void stop() throws Exception {
        System.out.println("status: " + status);
        System.out.println("stop...");
        status = "STOPED";
        this.thread.join(10);
        System.out.println("stop OK.");
        System.out.println();
    }
 
    @Override
    public void destroy() {
        System.out.println("status: " + status);
        System.out.println("destroy...");
        status = "DESTROIED";
        System.out.println("destory OK.");
        System.out.println();
    }
 
    @Override
    public void run() {
        while(true) {
            System.out.println(no);
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            if (no > 1000) {
                break;
            }
            no++;
        }
    }
}

 

// 작성한 프로그램 컴파일 하기

# javac TestDaemon.java

 

// 생성된 클래스 파일을 .jar파일로 묶기

# jar -cvf TestDaemon.jar TestDaemon.class

※ 기존에 .jar 파일이 있다면, Update를 하면 된다.  # jar -uvf [기존.jar] [새로운.class]

 

3. Java를 실행할 쉘 스크립트 파일 작성하기

디버깅의 편의성을 위해 에러 출력을 표준 출력과 같은 파일에 저장하도록 함

 

File name : TestDaemon.sh

#!/bin/sh
JSVC=/root/dwp/commons-daemon/jsvc      # [*] jsvc 경로를 입력
USER=root
 
DAEMON_HOME=/root/dwp/commons-daemon    # [*] 실제 작업하는 경로를 입력
PID_FILE=$DAEMON_HOME/daemon.pid
OUT_FILE=$DAEMON_HOME/daemon.out
ERR_FILE=$DAEMON_HOME/daemon.err
 
CLASSPATH=\
$DAEMON_HOME/commons-daemon-1.1.0.jar:\ # [*] commons-daemon-*.jar 파일이 존재하는 위치를 입력
$DAEMON_HOME/TestDaemon.jar             # [*] 아까전에 만든 .jar 파일이 존재하는 위치를 입력
 
MAIN_CLASS=TestDaemon                   # [*] 메인클래스 입력 (ex, TestDaemon)
case "$1" in
  start)
    #
    # Start Daemon
    #
    rm -f $OUT_FILE
    $JSVC \
    -user $USER \
    -java-home $JAVA_HOME \
    -pidfile $PID_FILE \
    -outfile $OUT_FILE \
    -errfile $ERR_FILE \
    -cp $CLASSPATH \
    $MAIN_CLASS
    # To get a verbose JVM
#    -verbose \
    # To get a debug of jsvc.
#    -debug \
    exit $?
    ;;
 
  stop)
    #
    # Stop Daemon
    #
    $JSVC \
    -stop \
    -nodetach \
    -java-home $JAVA_HOME \
    -pidfile $PID_FILE \
    -outfile $OUT_FILE \
    -errfile $ERR_FILE \
    -cp $CLASSPATH \
    $MAIN_CLASS
    exit $?
    ;;
 
  *)
    echo "[Usage] TestDaemon.sh start | stop"
    exit 1;;
esac

 

4. 실행 및 종료

// 실행하기

# /root/common-daemon/TestDaemon.sh start

// 종료하기

# /root/common-daemon/TestDaemon.sh stop

 

실행하기를 했을 때, 현재 디렉토리에 daemon.err 파일과 daemon.out 파일을 볼 수 있을 것이다.

만약 데몬 프로그램 실행이 되지 않았을 때는 '.err' 파일을 열어보면 그 이유를 알 수 있다. '.out' 파일은 프로그램 실행이 성공하고 실행한 결과를 출력한다.

 

[그림] # cat 명령어를 사용해서 daemon.out 파일을 실행한 화면이다.

 

 

 

 

 

 

 

ref) http://ir.bagesoft.com/640

http://lyb1495.tistory.com/11