永远不会使用jSch读取服务器响应

我试图通过连接jSch0.1.49库在unix服务器上运行命令。 我已经浏览了jSch提供的示例甚至http://sourceforge.net/apps/mediawiki/jsch/index.php?title=Official_examples

我能够从服务器读取响应并将其打印到控制台,但循环是* 永远不会结束 * g。 我怀疑为什么Channele一旦完成读取服务器的响应就不会关闭。

while (true) { while (inputStream.available() > 0) { int i = inputStream.read(buffer, 0, 1024); if (i < 0) { break; } System.out.print(new String(buffer, 0, i));//It is printing the response to console } System.out.println("done");// It is printing continuously infinite times if (channel.isClosed()) {//It is never closed System.out.println("exit-status: " + channel.getExitStatus()); break; } try{Thread.sleep(1000);}catch(Exception ee){} } 

当没有输入时,通道不会自行关闭。 阅读完所有数据后,请尝试自行关闭它。

 while (true) { while (inputStream.available() > 0) { int i = inputStream.read(buffer, 0, 1024); if (i < 0) { break; } System.out.print(new String(buffer, 0, i));//It is printing the response to console } System.out.println("done"); channel.close(); // this closes the jsch channel if (channel.isClosed()) { System.out.println("exit-status: " + channel.getExitStatus()); break; } try{Thread.sleep(1000);}catch(Exception ee){} } 

当您从用户输入交互式键盘时,您唯一一次使用不会手动关闭通道的循环。 然后,当用户执行“退出”时,将更改频道的'getExitStatus'。 如果你的循环是while(channel.getExitStatus()== -1),那么当用户退出时循环将退出。 检测到退出状态后,您仍需要自行断开通道和会话

它未在其示例页面上列出,但JSCH在其站点上托管了交互式键盘演示。 http://www.jcraft.com/jsch/examples/UserAuthKI.java

甚至他们的演示,我曾经连接到AIX系统而不改变他们的任何代码......当你退出shell时它不会关闭!

在我的远程会话中键入“exit”后,我必须添加以下代码才能使其正常退出:

  channel.connect(); // My added code begins here while (channel.getExitStatus() == -1){ try{Thread.sleep(1000);}catch(Exception e){System.out.println(e);} } channel.disconnect(); session.disconnect(); // My Added code ends here } catch(Exception e){ System.out.println(e); } } 

我认为比轮询退出状态更好的方法是等待Channel.thread的结束

 Thread t = channel.getThread(); if(t != null) { synchronized(t){ t.wait(); } System.out.println("Channel thread completed, disconnecting session"); session.disconnect(); } 

我已经向Channel添加了一个getThread()成员,它只返回当前的通道线程,我也修改了Channel.disconnect(),这样如果线程仍处于活动状态,则线程成员不会设置为零

 if(thread != null) { if(!thread.isAlive()) thread = null; } 

代替

 thread = null; 

在Channel.disconnect()中

我发现上面给出的解决方案会挂起。 我的解决方案删除了​​“while(true)”,选择了更直接的方法。

  private void sendCommand(Channel channel, String command) { try { // this.channelExec = (ChannelExec) channel; this.channelExec.setCommand(command); //channel.setInputStream(null); channel.setOutputStream(System.out); this.is = channel.getInputStream(); channel.connect(); byte[] buffer = new byte[1024]; while (channel.getExitStatus() == -1) { while (is.available() > 0) { int i = is.read(buffer, 0, 1024); // System.out.println("i= " + i); if (i < 0) { // System.out.println("breaking"); break; } String string = new String(buffer, 0, i); output = output.concat(string); //System.out.println("String= " + string); } if (channel.isClosed()) { //System.out.println("exit-status: " + channel.getExitStatus()); break; } } is.close(); channel.disconnect(); this.session.disconnect(); System.out.println("Done"); } catch (IOException ex) { System.out.println("ERROR: " + ex); Logger.getLogger(SSH.class.getName()).log(Level.SEVERE, null, ex); } catch (JSchException ex) { System.out.println("ERROR: " + ex); Logger.getLogger(SSH.class.getName()).log(Level.SEVERE, null, ex); } } 

我还尝试使用jSch远程执行多个命令并获取命令输出到控制台(标准输出System.out )。 还要等到所有命令在远程计算机上完全执行。

在摆弄了很多并且谷歌搜索了几个小时之后,我能够想出以下内容:

 import java.io.InputStream; import com.jcraft.jsch.ChannelExec; import com.jcraft.jsch.JSch; import com.jcraft.jsch.Session; public class SSHUtility { public static void main(String[] args) { //Separate multiple commands by semicolon //Do not separate commands with `exit` command, otherwise //commands following `exit` will not execute String commands = "source ~/Downloads/helloworld.sh;echo Mahesha999"; executeCommand("username", "password", "hostname", 22, commands); System.out.println("done"); } public static void executeCommand(String pUser, String pPassword, String pServer, int pPort, String pCommand) { System.out.println("Executing on ssh"); JSch lJSCH; Session lSession; lJSCH = new JSch(); try { lSession = lJSCH.getSession(pUser, pServer, pPort); lSession.setConfig("StrictHostKeyChecking", "no"); lSession.setPassword(pPassword); System.out.println("Connecting session..."); lSession.connect(); System.out.println("Session connected."); ChannelExec lChannelExec = (ChannelExec)lSession.openChannel("exec"); lChannelExec.setCommand(pCommand); ((ChannelExec)lChannelExec).setErrStream(System.err); InputStream ins=lChannelExec.getInputStream(); System.out.println("Connecting exec channel..."); lChannelExec.connect(); System.out.println("exec channel connected."); byte[] tmp=new byte[1024]; System.out.println("Trying to read remote command output..."); while(true) { while(ins.available()>0) { int i=ins.read(tmp, 0, 1024); if(i<0)break; System.out.print(new String(tmp, 0, i)); } if(lChannelExec.isClosed()) { if(ins.available()>0) continue; System.out.println("exit-status: "+lChannelExec.getExitStatus()); break; } try{Thread.sleep(1000);}catch(Exception ee){} } lChannelExec.disconnect(); lSession.disconnect(); } catch(Exception e) { System.out.println(e); } } } /* Output: Executing on ssh Connecting session... Session connected. Connecting exec channel... exec channel connected. Trying to read remote command output... Hello Mahesha999 exit-status: 0 done */ 

如果您的命令格式正确,我发现只要您及时读取输出,Jsch将在命令完成后关闭通道。 在JCraft示例中,channel.isClosed()是他们检查命令完成的唯一内容。 他们在等待通道关闭的同一线程中读取输出。 更好的方法是创建一个单独的线程来读取输出。 示例如下:

Jsch代码:

  Channel channel = null; int exitStatus = 0; List lines = new ArrayList(); 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 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 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) { } } }