Java의 Runtime.exec ()를 사용할 때 시간 초과 값을 추가하는 방법은 무엇입니까?
로컬 호스트에서 명령을 실행하는 데 사용하는 방법이 있습니다. 호출되는 명령이 적절한 시간 내에 완료되지 않으면 메서드가 오류 코드와 함께 반환되도록 메서드에 시간 제한 매개 변수를 추가하고 싶습니다. 시간 초과 기능이없는 지금까지의 모습은 다음과 같습니다.
public static int executeCommandLine(final String commandLine,
final boolean printOutput,
final boolean printError)
throws IOException, InterruptedException
{
Runtime runtime = Runtime.getRuntime();
Process process = runtime.exec(commandLine);
if (printOutput)
{
BufferedReader outputReader = new BufferedReader(new InputStreamReader(process.getInputStream()));
System.out.println("Output: " + outputReader.readLine());
}
if (printError)
{
BufferedReader errorReader = new BufferedReader(new InputStreamReader(process.getErrorStream()));
System.out.println("Error: " + errorReader.readLine());
}
return process.waitFor();
}
누구든지 시간 초과 매개 변수를 구현하는 좋은 방법을 제안 할 수 있습니까?
public static int executeCommandLine(final String commandLine,
final boolean printOutput,
final boolean printError,
final long timeout)
throws IOException, InterruptedException, TimeoutException {
Runtime runtime = Runtime.getRuntime();
Process process = runtime.exec(commandLine);
/* Set up process I/O. */
...
Worker worker = new Worker(process);
worker.start();
try {
worker.join(timeout);
if (worker.exit != null)
return worker.exit;
else
throw new TimeoutException();
} catch(InterruptedException ex) {
worker.interrupt();
Thread.currentThread().interrupt();
throw ex;
} finally {
process.destroyForcibly();
}
}
private static class Worker extends Thread {
private final Process process;
private Integer exit;
private Worker(Process process) {
this.process = process;
}
public void run() {
try {
exit = process.waitFor();
} catch (InterruptedException ignore) {
return;
}
}
}
Java 8 이상을 사용하는 경우 timeout과 함께 새로운 waitFor를 사용할 수 있습니다 .
Process p = ...
if(!p.waitFor(1, TimeUnit.MINUTES)) {
//timeout - kill the process.
p.destroy(); // consider using destroyForcibly instead
}
erickson 의 답변에 따라 동일한 작업을 수행하는보다 일반적인 방법을 만들었습니다.
public class ProcessWithTimeout extends Thread
{
private Process m_process;
private int m_exitCode = Integer.MIN_VALUE;
public ProcessWithTimeout(Process p_process)
{
m_process = p_process;
}
public int waitForProcess(int p_timeoutMilliseconds)
{
this.start();
try
{
this.join(p_timeoutMilliseconds);
}
catch (InterruptedException e)
{
this.interrupt();
}
return m_exitCode;
}
@Override
public void run()
{
try
{
m_exitCode = m_process.waitFor();
}
catch (InterruptedException ignore)
{
// Do nothing
}
catch (Exception ex)
{
// Unexpected exception
}
}
}
이제 다음과 같이하면됩니다.
Process process = Runtime.getRuntime().exec("<your command goes here>");
ProcessWithTimeout processWithTimeout = new ProcessWithTimeout(process);
int exitCode = processWithTimeout.waitForProcess(5000);
if (exitCode == Integer.MIN_VALUE)
{
// Timeout
}
else
{
// No timeout !
}
자세한 코드 예제와 함께 제공되는 세 가지 접근 방식을 사용하여 구현했습니다 (저는 스레드 프로그래밍의 초보자이며 이러한 예제 코드는 매우 유용했습니다. 영어로만 설명했다면이 작업을 수행하는 방법에 대해 여전히 머리를 긁적입니다. 코드없이).
다음과 같은 시간 제한을 사용하여 명령을 실행하는 세 가지 방법으로 사용중인 유틸리티 클래스를 구현했습니다.
package com.abc.network.lifecycle.util;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* Utility class for performing process related functions such as command line processing.
*/
public class ProcessUtility
{
static Log log = LogFactory.getLog(ProcessUtility.class);
/**
* Thread class to be used as a worker
*/
private static class Worker
extends Thread
{
private final Process process;
private Integer exitValue;
Worker(final Process process)
{
this.process = process;
}
public Integer getExitValue()
{
return exitValue;
}
@Override
public void run()
{
try
{
exitValue = process.waitFor();
}
catch (InterruptedException ignore)
{
return;
}
}
}
/**
* Executes a command.
*
* @param command
* @param printOutput
* @param printError
* @param timeOut
* @return
* @throws java.io.IOException
* @throws java.lang.InterruptedException
*/
public static int executeCommandWithExecutors(final String command,
final boolean printOutput,
final boolean printError,
final long timeOut)
{
// validate the system and command line and get a system-appropriate command line
String massagedCommand = validateSystemAndMassageCommand(command);
try
{
// create the process which will run the command
Runtime runtime = Runtime.getRuntime();
final Process process = runtime.exec(massagedCommand);
// consume and display the error and output streams
StreamGobbler outputGobbler = new StreamGobbler(process.getInputStream(), "OUTPUT", printOutput);
StreamGobbler errorGobbler = new StreamGobbler(process.getErrorStream(), "ERROR", printError);
outputGobbler.start();
errorGobbler.start();
// create a Callable for the command's Process which can be called by an Executor
Callable<Integer> call = new Callable<Integer>()
{
public Integer call()
throws Exception
{
process.waitFor();
return process.exitValue();
}
};
// submit the command's call and get the result from a
Future<Integer> futureResultOfCall = Executors.newSingleThreadExecutor().submit(call);
try
{
int exitValue = futureResultOfCall.get(timeOut, TimeUnit.MILLISECONDS);
return exitValue;
}
catch (TimeoutException ex)
{
String errorMessage = "The command [" + command + "] timed out.";
log.error(errorMessage, ex);
throw new RuntimeException(errorMessage, ex);
}
catch (ExecutionException ex)
{
String errorMessage = "The command [" + command + "] did not complete due to an execution error.";
log.error(errorMessage, ex);
throw new RuntimeException(errorMessage, ex);
}
}
catch (InterruptedException ex)
{
String errorMessage = "The command [" + command + "] did not complete due to an unexpected interruption.";
log.error(errorMessage, ex);
throw new RuntimeException(errorMessage, ex);
}
catch (IOException ex)
{
String errorMessage = "The command [" + command + "] did not complete due to an IO error.";
log.error(errorMessage, ex);
throw new RuntimeException(errorMessage, ex);
}
}
/**
* Executes a command.
*
* @param command
* @param printOutput
* @param printError
* @param timeOut
* @return
* @throws java.io.IOException
* @throws java.lang.InterruptedException
*/
public static int executeCommandWithSleep(final String command,
final boolean printOutput,
final boolean printError,
final long timeOut)
{
// validate the system and command line and get a system-appropriate command line
String massagedCommand = validateSystemAndMassageCommand(command);
try
{
// create the process which will run the command
Runtime runtime = Runtime.getRuntime();
Process process = runtime.exec(massagedCommand);
// consume and display the error and output streams
StreamGobbler outputGobbler = new StreamGobbler(process.getInputStream(), "OUTPUT", printOutput);
StreamGobbler errorGobbler = new StreamGobbler(process.getErrorStream(), "ERROR", printError);
outputGobbler.start();
errorGobbler.start();
// run a thread which will set a flag once it has slept for the timeout period
final boolean[] flags = { true };
new Thread()
{
@Override
public void run()
{
try
{
Thread.sleep(timeOut);
}
catch (InterruptedException ex)
{
String errorMessage = "Timeout loop thread unexpectedly interrupted.";
log.error(errorMessage, ex);
throw new RuntimeException(errorMessage, ex);
}
flags[0] = false;
}
}.start();
// execute the command and wait
int returnValue = -1;
while (flags[0] && (returnValue < 0))
{
returnValue = process.waitFor();
}
// if the command timed out then log it
if (returnValue < 0)
{
log.warn("The command [" + command + "] did not complete before the timeout period expired (timeout: " +
timeOut + " ms)");
}
return returnValue;
}
catch (InterruptedException ex)
{
String errorMessage = "The command [" + command + "] did not complete due to an unexpected interruption.";
log.error(errorMessage, ex);
throw new RuntimeException(errorMessage, ex);
}
catch (IOException ex)
{
String errorMessage = "The command [" + command + "] did not complete due to an IO error.";
log.error(errorMessage, ex);
throw new RuntimeException(errorMessage, ex);
}
}
/**
* Executes a command.
*
* @param command
* @param printOutput
* @param printError
* @param timeOut
* @return
* @throws java.io.IOException
* @throws java.lang.InterruptedException
*/
public static int executeCommandWithWorker(final String command,
final boolean printOutput,
final boolean printError,
final long timeOut)
{
// validate the system and command line and get a system-appropriate command line
String massagedCommand = validateSystemAndMassageCommand(command);
try
{
// create the process which will run the command
Runtime runtime = Runtime.getRuntime();
Process process = runtime.exec(massagedCommand);
// consume and display the error and output streams
StreamGobbler outputGobbler = new StreamGobbler(process.getInputStream(), "OUTPUT", printOutput);
StreamGobbler errorGobbler = new StreamGobbler(process.getErrorStream(), "ERROR", printError);
outputGobbler.start();
errorGobbler.start();
// create and start a Worker thread which this thread will join for the timeout period
Worker worker = new Worker(process);
worker.start();
try
{
worker.join(timeOut);
Integer exitValue = worker.getExitValue();
if (exitValue != null)
{
// the worker thread completed within the timeout period
return exitValue;
}
// if we get this far then we never got an exit value from the worker thread as a result of a timeout
String errorMessage = "The command [" + command + "] timed out.";
log.error(errorMessage);
throw new RuntimeException(errorMessage);
}
catch (InterruptedException ex)
{
worker.interrupt();
Thread.currentThread().interrupt();
throw ex;
}
}
catch (InterruptedException ex)
{
String errorMessage = "The command [" + command + "] did not complete due to an unexpected interruption.";
log.error(errorMessage, ex);
throw new RuntimeException(errorMessage, ex);
}
catch (IOException ex)
{
String errorMessage = "The command [" + command + "] did not complete due to an IO error.";
log.error(errorMessage, ex);
throw new RuntimeException(errorMessage, ex);
}
}
/**
* Validates that the system is running a supported OS and returns a system-appropriate command line.
*
* @param originalCommand
* @return
*/
private static String validateSystemAndMassageCommand(final String originalCommand)
{
// make sure that we have a command
if (originalCommand.isEmpty() || (originalCommand.length() < 1))
{
String errorMessage = "Missing or empty command line parameter.";
log.error(errorMessage);
throw new RuntimeException(errorMessage);
}
// make sure that we are running on a supported system, and if so set the command line appropriately
String massagedCommand;
String osName = System.getProperty("os.name");
if (osName.equals("Windows XP"))
{
massagedCommand = "cmd.exe /C " + originalCommand;
}
else if (osName.equals("Solaris") || osName.equals("SunOS") || osName.equals("Linux"))
{
massagedCommand = originalCommand;
}
else
{
String errorMessage = "Unable to run on this system which is not Solaris, Linux, or Windows XP (actual OS type: \'" +
osName + "\').";
log.error(errorMessage);
throw new RuntimeException(errorMessage);
}
return massagedCommand;
}
}
명령 ( http://www.javaworld.com/javaworld/jw-12-2000/jw-1229-traps.html?page=4 에서 가져옴 ) 에서 출력 및 오류 스트림을 소비하고 표시하는 클래스를 만들었습니다 .
package com.abc.network.lifecycle.util;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* Utility thread class which consumes and displays stream input.
*
* Original code taken from http://www.javaworld.com/javaworld/jw-12-2000/jw-1229-traps.html?page=4
*/
class StreamGobbler
extends Thread
{
static private Log log = LogFactory.getLog(StreamGobbler.class);
private InputStream inputStream;
private String streamType;
private boolean displayStreamOutput;
/**
* Constructor.
*
* @param inputStream the InputStream to be consumed
* @param streamType the stream type (should be OUTPUT or ERROR)
* @param displayStreamOutput whether or not to display the output of the stream being consumed
*/
StreamGobbler(final InputStream inputStream,
final String streamType,
final boolean displayStreamOutput)
{
this.inputStream = inputStream;
this.streamType = streamType;
this.displayStreamOutput = displayStreamOutput;
}
/**
* Consumes the output from the input stream and displays the lines consumed if configured to do so.
*/
@Override
public void run()
{
try
{
InputStreamReader inputStreamReader = new InputStreamReader(inputStream);
BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
String line = null;
while ((line = bufferedReader.readLine()) != null)
{
if (displayStreamOutput)
{
System.out.println(streamType + ">" + line);
}
}
}
catch (IOException ex)
{
log.error("Failed to successfully consume and display the input stream of type " + streamType + ".", ex);
ex.printStackTrace();
}
}
}
완료하는 데 약 10 초가 걸리는 테스트 명령을 만들었습니다.
#!/bin/bash
sleep 10
echo 'TEST COMMAND RAN OK'
그런 다음 시간 제한 값 5 초 (명령이 실패해야 함)와 제한 시간 값이 15 초 (명령이 성공해야 함)로 호출하는 세 가지 다른 메서드를 테스트하는 테스트 프로그램을 만들었습니다.
package com.abc.network.lifecycle.util;
public class ProcessUtilityTester
{
/**
* @param args
*/
public static void main(final String[] args)
{
try
{
String command = args[0];
int exitValue = -1;
System.out.println("\n\n5000ms timeout With Executors:");
try
{
exitValue = -1;
exitValue = ProcessUtility.executeCommandWithExecutors(command, true, true, 5000);
}
catch (Exception ex)
{
ex.printStackTrace();
}
finally
{
System.out.println("\nExit value:" + exitValue);
}
System.out.println("\n\n5000ms timeout With Sleep:");
try
{
exitValue = -1;
exitValue = ProcessUtility.executeCommandWithSleep(command, true, true, 5000);
}
catch (Exception ex)
{
ex.printStackTrace();
}
finally
{
System.out.println("\nExit value:" + exitValue);
}
System.out.println("\n\n5000ms timeout With Worker:");
try
{
exitValue = -1;
exitValue = ProcessUtility.executeCommandWithWorker(command, true, true, 5000);
}
catch (Exception ex)
{
ex.printStackTrace();
}
finally
{
System.out.println("\nExit value:" + exitValue);
}
System.out.println("\n\n15000ms timeout With Executors:");
try
{
exitValue = -1;
exitValue = ProcessUtility.executeCommandWithExecutors(command, true, true, 15000);
}
catch (Exception ex)
{
ex.printStackTrace();
}
finally
{
System.out.println("\nExit value:" + exitValue);
}
System.out.println("\n\n15000ms timeout With Sleep:");
try
{
exitValue = -1;
exitValue = ProcessUtility.executeCommandWithSleep(command, true, true, 15000);
}
catch (Exception ex)
{
ex.printStackTrace();
}
finally
{
System.out.println("\nExit value:" + exitValue);
}
System.out.println("\n\n15000ms timeout With Worker:");
try
{
exitValue = -1;
exitValue = ProcessUtility.executeCommandWithWorker(command, true, true, 15000);
}
catch (Exception ex)
{
ex.printStackTrace();
}
finally
{
System.out.println("\nExit value:" + exitValue);
}
}
catch (Exception ex)
{
ex.printStackTrace();
}
finally
{
System.exit(0);
}
}
}
테스트 프로그램을 실행하면 다음과 같이 표시됩니다.
5000ms timeout With Executors:
May 1, 2009 1:55:19 AM com.abc.network.lifecycle.util.ProcessUtility executeCommandWithExecutors
SEVERE: The command [/tmp/testcmd.sh] timed out.
java.util.concurrent.TimeoutException
at java.util.concurrent.FutureTask$Sync.innerGet(FutureTask.java:228)
at java.util.concurrent.FutureTask.get(FutureTask.java:91)
at com.abc.network.lifecycle.util.ProcessUtility.executeCommandWithExecutors(ProcessUtility.java:179)
at com.abc.network.lifecycle.util.ProcessUtilityTester.main(ProcessUtilityTester.java:19)
java.lang.RuntimeException: The command [/tmp/testcmd.sh] timed out.
at com.abc.network.lifecycle.util.ProcessUtility.executeCommandWithExecutors(ProcessUtility.java:186)
at com.abc.network.lifecycle.util.ProcessUtilityTester.main(ProcessUtilityTester.java:19)
Caused by: java.util.concurrent.TimeoutException
at java.util.concurrent.FutureTask$Sync.innerGet(FutureTask.java:228)
at java.util.concurrent.FutureTask.get(FutureTask.java:91)
at com.abc.network.lifecycle.util.ProcessUtility.executeCommandWithExecutors(ProcessUtility.java:179)
... 1 more
Exit value:-1
5000ms timeout With Sleep:
OUTPUT>TEST COMMAND RAN OK
OUTPUT>TEST COMMAND RAN OK
Exit value:0
5000ms timeout With Worker:
May 1, 2009 1:55:34 AM com.abc.network.lifecycle.util.ProcessUtility executeCommandWithWorker
SEVERE: The command [/tmp/testcmd.sh] timed out.
java.lang.RuntimeException: The command [/tmp/testcmd.sh] timed out.
at com.abc.network.lifecycle.util.ProcessUtility.executeCommandWithWorker(ProcessUtility.java:338)
at com.abc.network.lifecycle.util.ProcessUtilityTester.main(ProcessUtilityTester.java:47)
Exit value:-1
15000ms timeout With Executors:
OUTPUT>TEST COMMAND RAN OK
OUTPUT>TEST COMMAND RAN OK
Exit value:0
15000ms timeout With Sleep:
OUTPUT>TEST COMMAND RAN OK
Exit value:0
15000ms timeout With Worker:
OUTPUT>TEST COMMAND RAN OK
Exit value:0
따라서 작업자 스레드 클래스를 사용하는 접근 방식이 두 경우 모두에서 예상되는 결과를 제공한다는 점에서 가장 잘 작동합니다. Executors를 사용하는 접근 방식은 예상대로 작동하며 15000ms 시간 초과 경우 명령을 두 번 실행하는 것으로 보입니다 (즉, 명령에 대한 출력이 두 번 표시됨). sleep () 메서드를 사용하는 접근 방식은 5000ms 타임 아웃의 경우 예상대로 명령을 타임 아웃하지 않고 출력을 두 번 표시하지만 15000ms 타임 아웃의 경우 예상대로 명령을 실행합니다.
실행기 프레임 워크를 사용하는 모든 사람 : 실행기를 종료하는 것을 모두 잊고 있습니다. 따라서 다음과 같이 변경하십시오.
ExecutorService service = Executors.newSingleThreadExecutor();
try {
Future<Integer> ft = service.submit(call);
try {
int exitVal = ft.get(2000L, TimeUnit.MILLISECONDS);
return exitVal;
} catch (TimeoutException to) {
p.destroy();
throw to;
}
}
finally {
service.shutdown();
}
그렇지 않으면 프로그램이 활성 비 데몬 스레드를 유지하여 System.exit를 호출 할 때까지 프로그램이 종료되지 않도록합니다.
새로운 Java 8 방법을 사용할 수없는 경우 waitFor(long timeout, TimeUnit unit)
(Android에 있거나 단순히 업그레이드 할 수 없기 때문에) JDK 소스 코드에서 간단히 추출하여 utils 파일에 추가 할 수 있습니다.
public boolean waitFor(long timeout, TimeUnit unit, final Process process)
throws InterruptedException
{
long startTime = System.nanoTime();
long rem = unit.toNanos(timeout);
do {
try {
process.exitValue();
return true;
} catch(IllegalThreadStateException ex) {
if (rem > 0)
Thread.sleep(
Math.min(TimeUnit.NANOSECONDS.toMillis(rem) + 1, 100));
}
rem = unit.toNanos(timeout) - (System.nanoTime() - startTime);
} while (rem > 0);
return false;
}
JDK8 소스 코드에서 원래 변경 한 사항 은 프로세스 Process
에서 exitValue
메서드를 호출 할 수 있도록 매개 변수를 추가 한 것뿐입니다 .
이 exitValue
메서드는 IllegalThreadStateException
프로세스가 아직 종료되지 않은 경우 직접 반환하거나 throw를 시도합니다 . 이 경우 수신 된 타임 아웃을 기다렸다가 종료합니다.
이 메서드는 부울을 반환하므로 false를 반환하면 수동으로 프로세스를 종료해야합니다.
이 방법은 위에 게시 된 것보다 간단 해 보입니다 (확실히 waitFor에 대한 직접 호출을 예상).
소형 앱을위한 경량 솔루션 :
public class Test {
public static void main(String[] args) throws java.io.IOException, InterruptedException {
Process process = new ProcessBuilder().command("sleep", "10").start();
int i=0;
boolean deadYet = false;
do {
Thread.sleep(1000);
try {
process.exitValue();
deadYet = true;
} catch (IllegalThreadStateException e) {
System.out.println("Not done yet...");
if (++i >= 5) throw new RuntimeException("timeout");
}
} while (!deadYet);
}
}
대리인으로 구현하고 완료하는 데 임계 값을 초과하는 경우 호출을 실패합니다.
타이머 (또는 Sleep ()), 별도의 스레드 또는 사용 가능한 경우 이벤트 대기열에서 사용해보십시오.
이 작업을 수행하는 방법에는 여러 가지가 있지만 Executor를 사용하는 것이 좋습니다. 스레드의 종료 값이나 예외를 원래 호출자에게 다시 전달하는 것을 캡슐화하는 데 도움이됩니다.
final Process p = ...
Callable<Integer> call = new Callable<Integer>() {
public Integer call() throws Exception {
p.waitFor();
return p.exitValue();
}
};
Future<Integer> ft = Executors.newSingleThreadExecutor().submit(call);
try {
int exitVal = ft.get(2000L, TimeUnit.MILLISECONDS);
return exitVal;
} catch (TimeoutException to) {
p.destroy();
throw to;
}
나는 당신이 기다리는 시간이 초과되는 경쟁 조건을 극복 할 수 없다고 생각하고 destroy ()를 호출하기 직전에 프로세스가 종료됩니다.
또한 작업자 구현을 테스트했으며 매력처럼 작동합니다. 프로세스 io 처리에서 stde 및 stdo를 처리하는 스레드를 추가했습니다. 작업자 스레드가 시간 초과되면 io 스레드도 종료됩니다.
Process p = Runtime.getRuntime().exec(cmd.trim());
//setup error and output stream threads
CommandStreamThread eStream = new CommandStreamThread(p.getErrorStream(), "STDE");
CommandStreamThread oStream = new CommandStreamThread(p.getInputStream(), "STDO");
// kick them off
eStream.start();
oStream.start();
//setup a worker thread so we can time it out when we need
CommandWorkerThread worker=new CommandWorkerThread(p);
worker.start();
try {
worker.join(this.getTimeout());
if (worker.getExit() != null)
return worker.getExit();
else
throw new TimeoutException("Timeout reached:"+this.getTimeout()+" ms");
} catch(InterruptedException ex) {
eStream.interrupt();
oStream.interrupt();
worker.interrupt();
Thread.currentThread().interrupt();
throw ex;
} finally {
p.destroy();
}
먼저 몇 가지 배경 정보, 실행하려고 한 프로그램이 오류 발생시 디버그 또는 오류 정보를 인쇄하지 않고 자체적으로 내부적으로 계속 재 시도하여 프로세스가 중단되기 때문에 명령을 실행하는 동안 시간 초과가 발생하는 문제를 발견했습니다. 재 시도 할 때 오류나 출력 스트림이 없었기 때문입니다.
따라서 process.exec()
또는 이후 process.start()
,
이 줄에 영원히 갇혀있을 것입니다.
BufferedReader input = new BufferedReader(newInputStreamReader(process.getInputStream()));
public boolean waitFor(long timeout,TimeUnit unit)
메서드를 사용하는 Java 1.8에 따라 지정된 시간 초과 후에 "이상적으로"시간이 초과되어야하지만, 내 경우에는 Windows 서비스로 응용 프로그램을 실행했기 때문에 시간이 초과되지 않았을 수 있습니다 (사용자 권한과 모든 것을 확인했습니다 계정이지만 도움이되지 않았습니다).
그래서 아래 로직으로 구현하려고했는데, 입력 스트림과 input.ready()
타임 아웃 플래그를 계속 확인하는 것이 었습니다.
암호:
public boolean runCommand() throws IOException, InterruptedException, Exception {
StringBuilder rawResponse = new StringBuilder();
System.out.println("Running Command " + Arrays.toString(command));
ProcessBuilder processBuilder = new ProcessBuilder(Arrays.asList(command));
processBuilder.redirectErrorStream(true);
Process process = processBuilder.start(); //Executing the process
BufferedReader input = new BufferedReader(new InputStreamReader(process.getInputStream()));
waitForTimeout(input, process); //Waiting for Timout
String line;
while ((line = input.readLine()) != null) {
rawResponse.append(line).append("\n");
}
return true;
}
//Timeout method
private void waitForTimeout(BufferedReader input, Process process) throws InterruptedException, Exception {
int timeout = 5;
while (timeout > 0) {
if (input.ready()) {
break;
} else {
timeout--;
Thread.sleep(1000);
if (timeout == 0 && !input.ready()) {
destroyProcess(process);
throw new Exception("Timeout in executing the command "+Arrays.toString(command));
}
}
}
}
원하는 시간 동안 휴면하는 스레드를 시작할 수 있으며 휴면 후에 executeCommandLine 메서드에서 반복하는 부울을 변경할 수 있습니다.
다음과 같은 것 (테스트 또는 컴파일되지 않음,이 솔루션은 필요에 따라 리팩토링해야하는 프로토 타입입니다) :
public static int executeCommandLine(final String commandLine,
final boolean printOutput,
final boolean printError)
throws IOException, InterruptedException
{
Runtime runtime = Runtime.getRuntime();
Process process = runtime.exec(commandLine);
if (printOutput)
{
BufferedReader outputReader = new BufferedReader(new InputStreamReader(process.getInputStream()));
System.out.println("Output: " + outputReader.readLine());
}
if (printError)
{
BufferedReader errorReader = new BufferedReader(new InputStreamReader(process.getErrorStream()));
System.out.println("Error: " + errorReader.readLine());
}
ret = -1;
final[] b = {true};
new Thread(){
public void run(){
Thread.sleep(2000); //to adapt
b[0] = false;
}
}.start();
while(b[0])
{
ret = process.waitFor();
}
return ret;
}
여기에 StreamThread가 있습니다.
public class CommandStreamThread extends Thread{
private InputStream iStream;
private String cPrompt;
CommandStreamThread (InputStream is, String cPrompt)
{
this.iStream = is;
this.cPrompt = cPrompt;
}
public void run()
{
try
{
InputStreamReader streamReader= new InputStreamReader(this.iStream);
BufferedReader reader = new BufferedReader(streamReader);
String linesep=System.getProperty("line.separator");
String line=null;
while ((line=reader.readLine())!=null){
System.out.println(line);
//Process the next line seperately in case this is EOF is not preceded by EOL
int in;
char[] buffer=new char[linesep.length()];
while ( (in = reader.read(buffer)) != -1){
String bufferValue=String.valueOf(buffer, 0, in);
System.out.print(bufferValue);
if (bufferValue.equalsIgnoreCase(linesep))
break;
}
}
//Or the easy way out with commons utils!
//IOUtils.copy(this.iStream, System.out);
} catch (Exception e){
e.printStackTrace();
}
}
public InputStream getIStream() {
return iStream;
}
public void setIStream(InputStream stream) {
iStream = stream;
}
public String getCPrompt() {
return cPrompt;
}
public void setCPrompt(String prompt) {
cPrompt = prompt;
}
}
Apache Commons Exec이이를 지원할 수 있습니다.
http://commons.apache.org/proper/commons-exec/tutorial.html 참조
String line = "your command line";
CommandLine cmdLine = CommandLine.parse(line);
DefaultExecutor executor = new DefaultExecutor();
ExecuteWatchdog watchdog = new ExecuteWatchdog(60000);
executor.setWatchdog(watchdog);
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
PumpStreamHandler streamHandler = new PumpStreamHandler(outputStream);
executor.setStreamHandler(streamHandler);
int exitValue = executor.execute(cmdLine);
System.out.println(exitValue);
System.out.println(outputStream.toString());
Java 8을 사용하는 경우 Aleksander Blomskøld 대답 iepwaitFor (1, TimeUnit.MINUTE)를 사용합니다.
그렇지 않으면 Java 6/7 및 Swing을 사용하는 경우 SwingWorker를 사용할 수 있습니다.
final Process process = ...
SwingWorker<Integer, Integer> sw = new SwingWorker<>() {
@Override
protected Integer doInBackground() throws Exception {
process.waitFor();
return process.exitValue();
}
};
sw.execute();
int exitValue = sw.get(1, TimeUnit.SECONDS);
if (exitValue == 0) {
//everything was fine
} else {
//process exited with issues
}
나는 이것이 정말로 오래된 포스트라는 것을 안다. 비슷한 프로젝트에 대한 도움이 필요했기 때문에 내가 작업 한 코드와 작동하는 코드를 줄 수 있다고 생각했습니다.
long current = System.currentTimeMillis();
ProcessBuilder pb = new ProcessBuilder(arguments);
try{
pb.redirectErrorStream(true);
process = pb.start();
int c ;
while((c = process.getInputStream().read()) != -1 )
if(System.currentTimeMillis() - current < timeOutMilli)
result += (char)c;
else throw new Exception();
return result.trim();
}catch(Exception e){
e.printStackTrace();
}
return result;
이것이 미래에 도움이되기를 바랍니다.
참고 URL : https://stackoverflow.com/questions/808276/how-to-add-a-timeout-value-when-using-javas-runtime-exec
'programing tip' 카테고리의 다른 글
* nix에서 로그인 할 때 스크립트를 어떻게 실행합니까? (0) | 2020.11.07 |
---|---|
iPhone Simulator : SpringBoard가 오류로 인해 응용 프로그램을 시작하지 못했습니다 : 7 (0) | 2020.11.07 |
C에서 "함수 유형 충돌"을 얻는 이유는 무엇입니까? (0) | 2020.11.07 |
Microsoft의 데이터베이스 명명 규칙? (0) | 2020.11.07 |
web.xml을 사용하여 Spring에서 컨텍스트로드 (0) | 2020.11.07 |