가. 프로세스 생성 및 종료
일반적으로 프로그램을 실행시키면, 하나의 프로세스로서 동작하게 됩니다. 다시 말해서, 우리가 실행시키는 하나의 프로그램은 하나의 프로세스로서 나타나게 됩니다. 자바에서의 프로세스는 자바 런타임 환경과 밀접한 관계를 갖고 있습니다. 왜냐하면, 자바 런타임 환경은 프로세스가 실행될 수 있는 기반 환경을 제공해 주기 때문입니다. 프로세스는 다른 프로세스를 생성할 수 있는데, 이 때 생성된 프로세스를 자식 프로세스라하고 기존에 있던 프로세스를 부모 프로세스라 합니다. 이러한 부모/자식 프로세스 개념은 하나의 자바 프로그램에서 다른 프로그램을 실행시키고자 할 때, 주로 사용됩니다. 다시 말해서, 플랫폼 독립적인 자바 프로그램이 플랫폼과 밀접한 관련이 있는 작업을 해야 할 경우, 해당 작업을 수행할 프로그램을 다른 언어로 해당 플랫폼에 맞도록 작성하고, 이 프로그램을 자바 프로그램에서 실행시켜 주는 것입니다.
이를 위해, 플랫폼 종속적인 시스템 함수들을 호출할 수 있도록 해 주는 Runtime 클래스와 실행하고자 하는 응용프로그램을 위한 프로세스를 관리할 수 있도록 해 주는 Process 클래스를 사용할 수 있습니다. 자바에서 프로세스를 생성하기 위하여 다음과 같이 해 줍니다.
- “Runtime runtime = Runtime.getRuntime();”: 런타임 객체를 생성합니다.
- “Process p = runtime.exec(“프로그램경로명”);”: exec 메소드를 이용하여 프로세스를 생성합니다.
위와 같이 프로세스를 생성할 수 있고, 프로세스의 작업을 마치거나 또는 프로세스를 강제고 종료하기 위해서는 다음 중 한 가지 방법으로 할 수 있습니다.
- “p.waitFor();”: 자식 프로세스가 종료될 때까지 기다립니다.
- “p.destroy();”: 부모 프로세스에서 자식 프로세스를 강제로 종료시킵니다.
- “System.exit(0);”: 부모 프로세스만 종료되고 자식 프로세스는 계속 실행됩니다.
Runtime 클래스가 제공해 주는 주요 메소드를 살펴보면 다음과 같습니다.
- public static Runtime getRuntime(): 현재 실행되고 있는 자바 애플리케이션과 관련된 런타임 객체를 리턴해 줍니다.
- public void exit(int status): 현재 자바 가상머신을 종료합니다. status 매개변수는 종료시의 상태값을 나타내며, 일반적으로 0 이외의 값은 비정상적으로 종료되었음을 의미합니다.
- public Process exec(String command) throws IOException: 주어진 명령어를 독립된 프로세스로 실행시켜 줍니다. exec(command, null)와 같이 실행시킨 것과 같습니다.
- public Process exec(String command, String envp[]) throws IOException: 주어진 명령어를 주어진 환경을 갖는 독립된 프로세스로 실행시켜 줍니다. 이 메소드는 명령어 문자열을 토큰으로 나누어 이 토큰들을 포함하고 있는 cmdarray라는 새로운 배열을 생성합니다. 그리고 나서 exec(cmdarray, envp)을 호출합니다.
- public Process exec(String cmdarray[]) throws IOException: 주어진 문자열 배열에 있는 명령어와 매개변수를 이용하여 독립된 프로세스로 실행시켜 줍니다. exec(cmdarray, null)을 호출합니다.
- public Process exec(String cmdarray[], String envp[]) throws IOException: 주어진 문자열 배열에 있는 명령어와 매개변수를 이용하여 주어진 환경을 갖는 독립된 프로세스로 실행시켜 줍니다. 문자열 배열 cmdarray에는 명령어와 명령행 인자들을 나타내고 있습니다.
- public native long freeMemory(): 시스템에 남아있는 메모리의 양을 얻습니다. 이 값은 항상 totalMemory() 메소드에 의해 얻어지는 값보다 작습니다.
- public native long totalMemory(): 자바 가상머신의 최대 메모리 크기를 얻습니다.
Process 클래스가 제공해 주는 주요 메소드를 살펴보면 다음과 같습니다.
- public abstract OutputStream getOutputStream(): 자식 프로세스의 출력 스트림을 얻습니다.
- public abstract InputStream getInputStream(): 자식 프로세스의 입력 스트림을 얻습니다.
- public abstract InputStream getErrorStream(): 자식 프로세스의 에러 스트림을 얻습니다.
- public abstract int waitFor() throws InterruptedException: 자식 프로세스가 종료될 때까지 기다립니다.
- public abstract int exitValue(): 자식 프로세스가 종료할 때의 상태값을 얻습니다.
- public abstract void destroy(): 자식 프로세스를 강제로 종료시킵니다.
다음에 나오는 자바 프로그램은 위의 Runtime 클래스 및 Process 클래스를 이용하여 새로운 프로세스를 생성하고 종료하는 과정을 보여주기 위해 윈도우의 계산기를 실행시키는 간단한 예제입니다.
import java.io.*; public class ProcessTest { static public void main(String args[]) { try { Process p1 = Runtime.getRuntime().exec("calc.exe"); Process p2 = Runtime.getRuntime().exec("freecell.exe"); Process p3 = Runtime.getRuntime().exec("Notepad.exe"); p1.waitFor(); p2.destroy(); System.out.println("Exit value of p1: "+p1.exitValue()); System.out.println("Exit value of p2: "+p2.exitValue()); } catch(IOException e) { System.out.println(e.getMessage()); } catch(InterruptedException e) { System.out.println(e.getMessage()); } System.exit(0); } } /* * Results: D:\AIIT\JAVA\06>java ProcessTest Exit value of p1: 0 Exit value of p2: 1 D:\AIIT\JAVA\06> */ |
<프로그램 1. ProcessTest.java>
나. 상호작용 명령어의 실행
그런데, 위와 같이 프로세스를 이용하여 방식으로 명령어를 실행하다 보면, 명령어에 따라 사용자에게 메시지를 출력하고 이에 대한 적절한 답을 사용자로부터 입력 받기를 원하는 명령어가 있습니다. 이러한 명령어를 상호작용(interactive) 명령어라고 합니다.
D:\AIIT\JAVA\06>ping 203.252.134.126 Pinging 203.252.134.126 with 32 bytes of data: Reply from 203.252.134.126: bytes=32 time<10ms TTL=128 Reply from 203.252.134.126: bytes=32 time<10ms TTL=128 Reply from 203.252.134.126: bytes=32 time<10ms TTL=128 Reply from 203.252.134.126: bytes=32 time<10ms TTL=128 D:\AIIT\JAVA\06> |
<그림 1. 상호작용 명령어의 실행>
그림에서와 같이 ping 명령어를 실행시키게 되면, ping 명령어는 그 실행 결과를 표준 출력을 이용하여 화면상에 출력해 줍니다. 이렇게 자바에서 실행시킨 프로세스가 출력하는 결과를 자바 프로그램은 알아야 하고, 또한 프로세스가 자바 프로그램으로부터 어떤 대답을 원할 경우가 있는데 이 때 사용자는 이에 대해 적절하게 답을 해 주어야 합니다. 이 때, ping 명령어는 메시지를 자신의 표준 출력에 장치에 출력하게 되는데, 이렇게 프로세스의 표준 출력을 자바 프로그램에서는 p.getInputStream 메소드를 이용하여 얻고, p.getOutputStream 메소드를 이용하여 프로세스의 표준 입력 장치에 쓰게 됩니다. 이 때, 한 가지 주의할 사항은 표준 출력 스트림에 대답을 쓴(write) 후, 꼭 flush 또는 close 메소드를 이용하여 표준 출력 스트림을 비워(flush) 주어야 합니다.
<그림 2. 자바 프로그램과 프로세스 간의 데이터의 전달>
다음에 나오는 자바 프로그램은 도스 상에서 상호작용 명령어를 사용하는 간단한 예제를 보여줍니다.
import java.io.*; import java.lang.*; public class InteractiveProcessTest { public static void main(String[] args) { try { Process p = Runtime.getRuntime().exec("ping 203.252.134.126"); byte[] msg = new byte[128]; int len; while((len=p.getInputStream().read(msg)) > 0) { System.out.print(new String(msg, 0, len)); } String rs = "\n"; byte[] rb = new byte[] { (byte)'\n' } ; //rs.getBytes(); OutputStream os = p.getOutputStream(); os.write(rb); os.close(); } catch (Exception e) { e.printStackTrace(); } } } /* * Results: D:\AIIT\JAVA\06>java InteractiveProcessTest Pinging 203.252.134.126 with 32 bytes of data: Reply from 203.252.134.126: bytes=32 time<10ms TTL=128 Reply from 203.252.134.126: bytes=32 time<10ms TTL=128 Reply from 203.252.134.126: bytes=32 time<10ms TTL=128 Reply from 203.252.134.126: bytes=32 time<10ms TTL=128 D:\AIIT\JAVA\06> */ |
<프로그램 2. InteractiveProcessTest.java>