명령이 제대로 나는 명령이 완료되면 Jsch 채널을 닫습니다 발견, 포맷 제공 적시에 출력을 읽는 한. JCraft 예제에서 채널.isClosed()는 명령 완료를 확인하는 유일한 것입니다. 채널을 닫을 때까지 기다리는 동일한 스레드에서 결과를 읽습니다. 더 좋은 방법은 별도의 스레드를 만들어 출력을 읽는 것입니다. 예는 다음과 같습니다
Jsch 코드 :
Channel channel = null;
int exitStatus = 0;
List<String> lines = new ArrayList<String>();
try {
channel = session.openChannel("exec");
((ChannelExec) channel).setCommand(command);
// Read output in separate thread
Thread stdoutReader = new InputStreamHandler(channel.getInputStream(), "STDOUT", lines);
// Run the command
((ChannelExec)channel).setCommand(command);
channel.connect();
// Start thread that reads output
stdoutReader.start();
// Poll for closed status
boolean channelClosed = channel.isClosed();
exitStatus = channel.getExitStatus();
boolean stdOutReaderAlive = stdoutReader.isAlive();
int loopCounter = 0;
while (!channelClosed) {
if (loopCounter % 60 == 0) {
log.info("SSH command '" + command + "' still in while loop checking for after " + (loopCounter/60) + " mins.");
}
loopCounter++;
Thread.sleep(1000);
channelClosed = channel.isClosed();
exitStatus = channel.getExitStatus();
stdOutReaderAlive = stdoutReader.isAlive();
}
log.info("SSH command '" + command + "' exited while loop with values: channelClosed=" + channelClosed + ", exitStatus=" + exitStatus + ", stdOutReaderAlive=" + stdOutReaderAlive);
// finish reading output
stdoutReader.join();
exitStatus = channel.getExitStatus();
log.info("SSH command '" + command + "' final exitStatus=" + exitStatus);
for (String line : lines) {
log.info("SSH output: " + line);
}
} catch (Exception e) {
throw new RuntimeException("Error occured processing SSH request. See nested exception for details.", e);
} finally {
// Always try to close the channel and session.
try {
channel.disconnect();
} catch(Exception e) {
this.log.error("Error - disconnecting channel", e);
}
try {
session.disconnect();
} catch(Exception e) {
this.log.error("Error - disconnecting session", e);
}
}
InputStreamHandler : 당신의 설명은
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.InterruptedIOException;
import java.util.List;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* A lot of debate on how to stop a thread... going with the method given here: http://www.javaspecialists.eu/archive/Issue056.html
*/
public class InputStreamHandler extends Thread {
protected Log logger = LogFactory.getLog(getClass());
private InputStream is = null;
private String type = null;
private StringBuilder buffer;
private List<String> lines;
public InputStreamHandler(InputStream is, String type) {
this.is = is;
this.type = type;
}
public InputStreamHandler(InputStream is, String type, StringBuilder buffer) {
this(is, type);
this.buffer = buffer;
}
public InputStreamHandler(InputStream is, String type, List<String> lines) {
this(is, type);
this.lines = lines;
}
public void run() {
try {
InputStreamReader isr = new InputStreamReader(is);
BufferedReader br = new BufferedReader(isr);
if (buffer != null) {
String line = null;
while ((line = br.readLine()) != null) {
buffer.append(line + "\n");
}
} else if (lines != null) {
String line = null;
while ((line = br.readLine()) != null) {
lines.add(line);
}
} else {
// just consume output
while (br.readLine() != null)
;
}
} catch (InterruptedIOException ioe) {
// when exception is thrown the interrupt flag is set to false... this will set it back to true
Thread.currentThread().interrupt();
} catch (IOException ioe) {
if (!isInterrupted()) {
throw new RuntimeException("Caught IQException for "
+ this.type + " " + this.getClass().getName() + ".",
ioe);
}
} finally {
closeInputStream();
}
}
@Override
public void interrupt() {
super.interrupt();
closeInputStream();
logger.info(this.type + " " + this.getClass().getName()
+ " thread was interrupted.");
}
private void closeInputStream() {
try {
is.close();
} catch (Exception e) {
}
}
}
감사합니다. 그것은 나의 의심을 제거했다. 그래서 제 경우에는 세션을 열어두고 UI 부분의 일부 사용자 활동을 기반으로 여러 명령을 실행하고 싶습니다. 내가 더 이상 문제에 직면하면 나는 이것을 시도하고 당신에게 돌아올 것입니다. –
버전 0.1.53을 사용하고 있으며 'close'라는 공용 메서드가 없습니다 (보호 된 메서드가 있습니다). 내 경험에 비추어 볼 때 Jsch는 일반적으로 명령이 성공적으로 완료되면 항상 채널을 닫을 것이지만, 성공할 경우 코드에서이를 파악할 수는 없습니다. 닫힌 채널이나 폐쇄 된 출력 또는 exitStatus! = 1을 확인하여 명령이 완료되었는지 확인하는 것이 합당한 것 같습니다. JCraft가이 질문/문제를 해결하길 바랍니다. – splashout
추가 테스트를 마친 후, 문제점이 channel.isClosed()가 true를 반환 할 때까지 읽을 수없는 출력과 관련이 있다고 판단했습니다. 명령의 출력이 너무 많으면 채널이 닫히지 않으므로 프로세스가 중단됩니다 (Linux btw에서 실행). 따라서 최소한 대화식이 아닌 프로세스에서는 출력을 적시에 읽는 한 명령이 완료되면 Jsch가 채널을 닫을 것입니다. 나는 이것이 java.lang.Process 용 API에서 언급 한 것과 비슷한 문제라고 생각한다. "즉각적인 실패로 인해 출력 스트림을 읽으면 차단 될 수 있습니다. – splashout