반응형
java로 데몬 형태의 프로그램을 작성할 경우가 있다.
이때 기동이야 java 커맨드로 실행을 하지만,
중지시키기 위해서는 Ctrl+C 를 하거나 백그라운드 실행시 Kill 을 시켜야 하거나 한다.
좀 더 있어보이기 위해 여타 다른 데몬처럼 start, stop 커맨드를 사용하도록 만들어 본다.
핵심은 shutdown 을 처리를 ServerSocket 을 열고 해당 포트에 대한 Socket 통신으로 이루어진다는 점이다. 만들고자 하는 데몬이 통신서버라면 기존 통신 포트 외에 컨트롤 포트를 하나 더 사용하는 것이다.
Tomcat 의 경우 server.xml 의 맨 처음에 나오는 것은 다음과 같다.
<Server port="8005" shutdown="SHUTDOWN" debug="0">
여기서 port 가 바로 shutdown 처리를 위한 포트이고, 이 포트에 shutdown 으로 설정된 SHUTDOWN을 소켓으로 보내면 Tomcat 이 중지된다.
아래는 톰캣과 유사한 형태로 작성한 소스이다.
실행/종료 : java Server start / java Server shutdown
이때 기동이야 java 커맨드로 실행을 하지만,
중지시키기 위해서는 Ctrl+C 를 하거나 백그라운드 실행시 Kill 을 시켜야 하거나 한다.
좀 더 있어보이기 위해 여타 다른 데몬처럼 start, stop 커맨드를 사용하도록 만들어 본다.
핵심은 shutdown 을 처리를 ServerSocket 을 열고 해당 포트에 대한 Socket 통신으로 이루어진다는 점이다. 만들고자 하는 데몬이 통신서버라면 기존 통신 포트 외에 컨트롤 포트를 하나 더 사용하는 것이다.
Tomcat 의 경우 server.xml 의 맨 처음에 나오는 것은 다음과 같다.
<Server port="8005" shutdown="SHUTDOWN" debug="0">
여기서 port 가 바로 shutdown 처리를 위한 포트이고, 이 포트에 shutdown 으로 설정된 SHUTDOWN을 소켓으로 보내면 Tomcat 이 중지된다.
아래는 톰캣과 유사한 형태로 작성한 소스이다.
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.security.AccessControlException;
import java.util.Date;
import java.util.Random;
import java.util.Timer;
import java.util.TimerTask;
public class Server {
private static final String COMMAND_SHUTDOWN = "shutdown";
private static final int COMMAND_PORT = 8099;
private boolean started;
private Random random;
private Timer timer;
private Server() {
this.started = false;
this.random = null;
this.timer = null;
}
private void start() {
// 여기서 서버가 수행하는 쓰레드를 start시킨다(반드시 쓰레드이어야 한다).
// 에로서 Timer를 사용하여 1초마다 메시지 출력...
this.timer = new Timer();
timer.scheduleAtFixedRate(
new TimerTask() {
public void run() {
if ( started )
System.out.println("1초마다 메시지");
}
}
,new Date(),1000 );
await();
}
private void stop() {
// 서버가 수행하던 쓰레드를 중지시킨다.
// 예로써 Timer 중지...
this.timer.cancel();
this.timer = null;
System.out.println("중지되었습니다.");
}
/**
* 서버소켓을 열고 shutdown 요청이 있을때까지 대기...
*/
protected void await() {
try {
ServerSocket serverSocket = null;
try {
serverSocket = new ServerSocket(COMMAND_PORT, 1, InetAddress.getByName("127.0.0.1"));
started = true;
} catch (IOException e) {
e.printStackTrace();
}
while ( started ) {
Socket socket = null;
InputStream stream = null;
try {
socket = serverSocket.accept();
socket.setSoTimeout(10*1000 ); // 타임아웃 10초...
stream = socket.getInputStream();
} catch (AccessControlException e) {
continue;
} catch (IOException e) {
System.exit(1);
}
StringBuffer command = new StringBuffer();
// Cut off to avoid DoS attack
int expected = 1024;
while ( expected < COMMAND_SHUTDOWN.length() ) {
if ( random == null )
random = new Random(System.currentTimeMillis());
expected += (random.nextInt() % 1024);
}
while ( expected > 0 ) {
int ch = -1;
try {
ch = stream.read();
} catch (IOException e) {
ch = -1;
}
// EOF
if (ch < 32) break;
command.append((char)ch);
expected--;
}
// 소켓을 닫는다.
try { socket.close(); } catch (IOException ignore) {}
String cmd = command.toString();
// shutdown 명령시 루프 중지
if ( COMMAND_SHUTDOWN.equals(cmd) ) {
break;
}
}
// 서버 소켓을 닫는다.
try { serverSocket.close(); } catch (IOException ignore) {}
} catch(Throwable t) {
t.printStackTrace();
} finally {
// 서버 종료 처리...
try { stop(); } catch (Throwable ignore) {}
}
}
/**
* 소켓으로 shutdown 커맨드를 보낸다.
*/
private static void shutdown() {
Socket socket = null;
OutputStream os = null;
try {
socket = new Socket("127.0.0.1", COMMAND_PORT);
os = socket.getOutputStream();
for (int i = 0; i < COMMAND_SHUTDOWN.length(); i++) {
os.write(COMMAND_SHUTDOWN.charAt(i));
}
os.flush();
} catch(Throwable t) {
t.printStackTrace();
System.exit(1);
} finally {
try { os.close(); } catch(Throwable t) {}
try { socket.close(); } catch(Throwable t) {}
}
}
public static void main(String[] args) {
try {
if ( COMMAND_SHUTDOWN.equals(args[0]) ) {
shutdown();
} else {
Server server = new Server();
server.start();
}
} catch (Throwable t) {
t.printStackTrace();
}
}
}
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.security.AccessControlException;
import java.util.Date;
import java.util.Random;
import java.util.Timer;
import java.util.TimerTask;
public class Server {
private static final String COMMAND_SHUTDOWN = "shutdown";
private static final int COMMAND_PORT = 8099;
private boolean started;
private Random random;
private Timer timer;
private Server() {
this.started = false;
this.random = null;
this.timer = null;
}
private void start() {
// 여기서 서버가 수행하는 쓰레드를 start시킨다(반드시 쓰레드이어야 한다).
// 에로서 Timer를 사용하여 1초마다 메시지 출력...
this.timer = new Timer();
timer.scheduleAtFixedRate(
new TimerTask() {
public void run() {
if ( started )
System.out.println("1초마다 메시지");
}
}
,new Date(),1000 );
await();
}
private void stop() {
// 서버가 수행하던 쓰레드를 중지시킨다.
// 예로써 Timer 중지...
this.timer.cancel();
this.timer = null;
System.out.println("중지되었습니다.");
}
/**
* 서버소켓을 열고 shutdown 요청이 있을때까지 대기...
*/
protected void await() {
try {
ServerSocket serverSocket = null;
try {
serverSocket = new ServerSocket(COMMAND_PORT, 1, InetAddress.getByName("127.0.0.1"));
started = true;
} catch (IOException e) {
e.printStackTrace();
}
while ( started ) {
Socket socket = null;
InputStream stream = null;
try {
socket = serverSocket.accept();
socket.setSoTimeout(10*1000 ); // 타임아웃 10초...
stream = socket.getInputStream();
} catch (AccessControlException e) {
continue;
} catch (IOException e) {
System.exit(1);
}
StringBuffer command = new StringBuffer();
// Cut off to avoid DoS attack
int expected = 1024;
while ( expected < COMMAND_SHUTDOWN.length() ) {
if ( random == null )
random = new Random(System.currentTimeMillis());
expected += (random.nextInt() % 1024);
}
while ( expected > 0 ) {
int ch = -1;
try {
ch = stream.read();
} catch (IOException e) {
ch = -1;
}
// EOF
if (ch < 32) break;
command.append((char)ch);
expected--;
}
// 소켓을 닫는다.
try { socket.close(); } catch (IOException ignore) {}
String cmd = command.toString();
// shutdown 명령시 루프 중지
if ( COMMAND_SHUTDOWN.equals(cmd) ) {
break;
}
}
// 서버 소켓을 닫는다.
try { serverSocket.close(); } catch (IOException ignore) {}
} catch(Throwable t) {
t.printStackTrace();
} finally {
// 서버 종료 처리...
try { stop(); } catch (Throwable ignore) {}
}
}
/**
* 소켓으로 shutdown 커맨드를 보낸다.
*/
private static void shutdown() {
Socket socket = null;
OutputStream os = null;
try {
socket = new Socket("127.0.0.1", COMMAND_PORT);
os = socket.getOutputStream();
for (int i = 0; i < COMMAND_SHUTDOWN.length(); i++) {
os.write(COMMAND_SHUTDOWN.charAt(i));
}
os.flush();
} catch(Throwable t) {
t.printStackTrace();
System.exit(1);
} finally {
try { os.close(); } catch(Throwable t) {}
try { socket.close(); } catch(Throwable t) {}
}
}
public static void main(String[] args) {
try {
if ( COMMAND_SHUTDOWN.equals(args[0]) ) {
shutdown();
} else {
Server server = new Server();
server.start();
}
} catch (Throwable t) {
t.printStackTrace();
}
}
}
실행/종료 : java Server start / java Server shutdown
반응형
'개발도 하냐?' 카테고리의 다른 글
XP 개발방법론 (0) | 2009.12.06 |
---|---|
JAVA Application 한글깨짐 해결 (0) | 2009.12.03 |
웹접근성을 보장하는 웹개발을 위한 고려사항 (0) | 2009.12.02 |
Cross Domain Script 해결법 (0) | 2009.12.01 |
HTML vs XHTML? (0) | 2009.12.01 |