前提是你的命令格式正確,我發現,一旦該命令完成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部分的一些用戶活動的多個命令。如果我面對更多問題,我會盡力做到這一點並回復您。 – 2013-05-03 10:22:13
我使用的版本是0.1.53,沒有名爲'close'的公共方法(有這樣一種受保護的方法)。根據我的經驗,當命令成功完成時,Jsch通常會(但並非總是)關閉通道,但我無法在代碼中找到成功發生這種情況的原因。似乎共識是檢查閉合通道或關閉輸出或exitStatus!= 1以瞭解命令是否完整。希望JCraft能解決這個問題。 – splashout 2016-08-04 18:52:28
經過進一步測試後,我確定我的問題與在channel.isClosed()返回true之前不會讀取輸出有關。如果命令的輸出太多,通道永遠不會關閉,因此進程會掛起(在Linux上運行)。所以,至少在一個非交互式的過程中,只要您及時讀取輸出,我就可以確認Jsch將在命令完成時關閉通道。我相信這是一個類似於java.lang.Process的API中提到的問題:「無法及時...讀取輸出流...可能會導致它阻塞。 – splashout 2016-08-04 23:32:18