2009-10-02 76 views
2

我有一个运行在Tomcat中的Java程序,它需要执行几个ssh和scp命令以及一些简单的命令,例如本地机器上的ls。我目前的方法遇到麻烦,因为每次执行ssh命令时都会超时。我可以在命令行上运行ssh命令而没有任何问题,但是当它从我的Java程序执行时会超时。我运行的是以root身份执行ssh命令的web应用程序(即,我以root用户身份启动Tomcat,将我的web应用程序代码部署为WAR文件),并且据我所知,正确的认证密钥都配置在两个本地和远程机器,至少我可以在命令行上以root身份执行ssh命令,而无需输入用户名或密码。我没有在我的Java程序正在执行的ssh命令中指定用户名或密码,因为我认为我可以在我的Java代码中运行相同的ssh命令,因为我可以在命令行执行该命令,但也许这是错误的假设和我的麻烦的原因。从我的Java程序执行ssh命令时超时

我已经制定执行命令执行的Java代码如下:

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 volatile 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 args command + arguments 
    */ 
    public static void execCommand(final String[] args) 
    { 
     try 
     { 
      Runtime.getRuntime().exec(args); 
     } 
     catch (IOException e) 
     { 
      // swallow it 
     } 

    } 

    /** 
    * Executes a command. 
    * 
    * @param command 
    * @param printOutput 
    * @param printError 
    * @param timeOut 
    * @return 
    * @throws java.io.IOException 
    * @throws java.lang.InterruptedException 
    */ 
    public static int executeCommand(final String command, 
            final boolean printOutput, 
            final boolean printError, 
            final long timeOut) 
    { 
     return executeCommandWithWorker(command, printOutput, printError, timeOut); 
    } 

    /** 
    * Executes a command and returns its output or error stream. 
    * 
    * @param command 
    * @return the command's resulting output or error stream 
    */ 
    public static String executeCommandReceiveOutput(final String command) 
    { 
     try 
     { 
      // create the process which will run the command 
      Runtime runtime = Runtime.getRuntime(); 
      final Process process = runtime.exec(command); 

      try 
      { 
       // consume the error and output streams 
       StreamGobbler outputGobbler = new StreamGobbler(process.getInputStream(), "OUTPUT", false); 
       StreamGobbler errorGobbler = new StreamGobbler(process.getErrorStream(), "ERROR", false); 
       outputGobbler.start(); 
       errorGobbler.start(); 

       // execute the command 
       if (process.waitFor() == 0) 
       { 
        return outputGobbler.getInput(); 
       } 
       return errorGobbler.getInput(); 
      } 
      finally 
      { 
       process.destroy(); 
      } 
     } 
     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 
    */ 
    @SuppressWarnings("unused") 
    private 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 via an Executor and get the result from a Future 
      ExecutorService executorService = Executors.newSingleThreadExecutor(); 
      try 
      { 
       Future<Integer> futureResultOfCall = executorService.submit(call); 
       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); 
      } 
      finally 
      { 
       executorService.shutdown(); 
       process.destroy(); 
      } 
     } 
     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 
    */ 
    private 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 

        // stop the output and error stream gobblers 
        outputGobbler.stopGobbling(); 
        errorGobbler.stopGobbling(); 

        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; 
      } 
      finally 
      { 
       process.destroy(); 
      } 
     } 
     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; 
    } 
} 

class StreamGobbler 
    extends Thread 
{ 
    static private Log log = LogFactory.getLog(StreamGobbler.class); 
    private InputStream inputStream; 
    private String streamType; 
    private boolean displayStreamOutput; 
    private final StringBuffer inputBuffer = new StringBuffer(); 
    private boolean keepGobbling = true; 

    /** 
    * 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; 
    } 

    /** 
    * Returns the output stream of the 
    * 
    * @return 
    */ 
    public String getInput() 
    { 
     return inputBuffer.toString(); 
    } 

    /** 
    * Consumes the output from the input stream and displays the lines consumed if configured to do so. 
    */ 
    @Override 
    public void run() 
    { 
     InputStreamReader inputStreamReader = new InputStreamReader(inputStream); 
     BufferedReader bufferedReader = new BufferedReader(inputStreamReader); 
     try 
     { 
      String line = null; 
      while (keepGobbling && inputStreamReader.ready() && ((line = bufferedReader.readLine()) != null)) 
      { 
       inputBuffer.append(line); 
       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(); 
     } 
     finally 
     { 
      try 
      { 
       bufferedReader.close(); 
       inputStreamReader.close(); 
      } 
      catch (IOException e) 
      { 
       // swallow it 
      } 
     } 
    } 

    public void stopGobbling() 
    { 
     keepGobbling = false; 
    } 
} 

我在Java程序中执行SSH命令,像这样:

ProcessUtility.executeCommand( “SSH” + physicalHostIpAddress +“virsh list \ | grep”+ newDomUName,false,false,3600000)

任何人都可以看到我在做什么错?顺便说一句,上面的代码是使用这篇文章作为指导开发的:http://www.javaworld.com/javaworld/jw-12-2000/jw-1229-traps.html。我并不擅长并发编程,所以或许我正在做一些头脑发热的事情 - 如果有的话,请随时指出。

非常感谢您的任何建议,意见等

- 詹姆斯

更新:我现在已经采取了谁回答我原来的问题,并有帮助的人的忠告编写了一个提供ssh和scp调用方法的类,它使用两个Java ssh库jsch(jsch-0.1.31)和sshtools(j2ssh-core-0.2.9)实现。但是,这些实现都没有起作用,因为在我甚至没有机会执行身份验证之前,它们在连接步骤都失败了。我期望我在运行代码的服务器上面临某种配置问题,但这并不明显,因为我可以在这些服务器上执行ssh和scp命令,而不会出现任何问题,因为在发出ssh或scp命令时命令行。我正在测试我的代码的Solaris服务器上都呈现以下为SSH -V的结果:

Sun_SSH_1.3,SSH协议1.5/2.0,OpenSSL的0x0090801f

下面是Java代码我已经写为此 - 如果任何人都可以在Java代码级别看到我做错了什么,那么请让我知道,如果是的话,请提前感谢您的帮助。

public class SecureCommandUtility 
{ 
    static Log log = LogFactory.getLog(SecureCommandUtility.class); 

    /** 
    * Performs a secure copy of a single file (using scp). 
    * 
    * @param localFilePathName 
    * @param username 
    * @param password 
    * @param remoteHost 
    * @param remoteFilePathName 
    * @param timeout 
    */ 
    public static void secureCopySingleFile(final String localFilePathName, 
              final String username, 
              final String password, 
              final String remoteHost, 
              final String remoteFilePathName, 
              final int timeout) 
    { 
     // basic validation of the parameters 
     if ((localFilePathName == null) || localFilePathName.isEmpty()) 
     { 
      // log the error and throw an exception 
      String errorMessage = "Error executing the secure copy -- the supplied local file path name parameter is null or empty."; 
      log.error(errorMessage); 
      throw new LifecycleException(errorMessage); 
     } 
     if ((username == null) || username.isEmpty()) 
     { 
      // log the error and throw an exception 
      String errorMessage = "Error executing the secure copy -- the supplied user name parameter is null or empty."; 
      log.error(errorMessage); 
      throw new LifecycleException(errorMessage); 
     } 
     if ((password == null) || password.isEmpty()) 
     { 
      // log the error and throw an exception 
      String errorMessage = "Error executing the secure copy -- the supplied password parameter is null or empty."; 
      log.error(errorMessage); 
      throw new LifecycleException(errorMessage); 
     } 
     if ((remoteHost == null) || remoteHost.isEmpty()) 
     { 
      // log the error and throw an exception 
      String errorMessage = "Error executing the secure copy -- the supplied remote host parameter is null or empty."; 
      log.error(errorMessage); 
      throw new LifecycleException(errorMessage); 
     } 
     if ((remoteFilePathName == null) || remoteFilePathName.isEmpty()) 
     { 
      // log the error and throw an exception 
      String errorMessage = "Error executing the secure copy -- the supplied remote file path name parameter is null or empty."; 
      log.error(errorMessage); 
      throw new LifecycleException(errorMessage); 
     } 
     if (timeout < 1000) 
     { 
      // log the error and throw an exception 
      String errorMessage = "Error executing the secure copy -- the supplied timeout parameter is less than one second."; 
      log.error(errorMessage); 
      throw new LifecycleException(errorMessage); 
     } 

     //secureCopySingleFileJSch(localFilePathName, username, password, remoteHost, remoteFilePathName); 
     secureCopySingleFileJ2Ssh(localFilePathName, username, password, remoteHost, remoteFilePathName, timeout); 
    } 

    /** 
    * 
    * @param user 
    * @param password 
    * @param remoteHost 
    * @param command 
    * @return exit status of the command 
    */ 
    public static int secureShellCommand(final String user, 
             final String password, 
             final String remoteHost, 
             final String command, 
             final int timeout) 
    { 
     // basic validation of the parameters 
     if ((user == null) || user.isEmpty()) 
     { 
      // log the error and throw an exception 
      String errorMessage = "Error executing the ssh command \'" + command + 
            "\': the supplied user name parameter is null or empty."; 
      log.error(errorMessage); 
      throw new LifecycleException(errorMessage); 
     } 
     if ((password == null) || password.isEmpty()) 
     { 
      // log the error and throw an exception 
      String errorMessage = "Error executing the ssh command \'" + command + 
            "\': the supplied password parameter is null or empty."; 
      log.error(errorMessage); 
      throw new LifecycleException(errorMessage); 
     } 
     if ((remoteHost == null) || remoteHost.isEmpty()) 
     { 
      // log the error and throw an exception 
      String errorMessage = "Error executing the ssh command \'" + command + 
            "\': the supplied remote host parameter is null or empty."; 
      log.error(errorMessage); 
      throw new LifecycleException(errorMessage); 
     } 
     if ((command == null) || command.isEmpty()) 
     { 
      // log the error and throw an exception 
      String errorMessage = "Error executing the ssh command: the supplied command parameter is null or empty."; 
      log.error(errorMessage); 
      throw new LifecycleException(errorMessage); 
     } 
     if (timeout < 1000) 
     { 
      // log the error and throw an exception 
      String errorMessage = "Error executing the ssh command \'" + command + 
            "\': the supplied timeout parameter is less than one second."; 
      log.error(errorMessage); 
      throw new LifecycleException(errorMessage); 
     } 

     //return secureShellCommandJsch(user, password, remoteHost, command, timeout); 
     return secureShellCommandJ2Ssh(user, password, remoteHost, command, timeout); 
    } 

    /** 
    * Performs a secure copy of a single file (using scp). 
    * 
    * @param localFilePathName 
    * @param username 
    * @param password 
    * @param remoteHost 
    * @param remoteFilePathName 
    * @param timeout 
    */ 
    private static void secureCopySingleFileJ2Ssh(final String localFilePathName, 
                final String username, 
                final String password, 
                final String remoteHost, 
                final String remoteFilePathName, 
                final int timeout) 
    { 
     SshClient sshClient = null; 
     try 
     { 
      // create and connect client 
      sshClient = new SshClient(); 
      sshClient.setSocketTimeout(timeout); 
      sshClient.connect(remoteHost, 22, new IgnoreHostKeyVerification()); 

      // perform password-based authentication 
      PasswordAuthenticationClient passwordAuthenticationClient = new PasswordAuthenticationClient(); 
      passwordAuthenticationClient.setUsername(username); 
      passwordAuthenticationClient.setPassword(password); 
      if (sshClient.authenticate(passwordAuthenticationClient) != AuthenticationProtocolState.COMPLETE) 
      { 
       // log the error and throw an exception 
       String errorMessage = "Failed to copy \'" + localFilePathName + "\' to \'" + remoteHost + ":" + 
             remoteFilePathName + "\' -- failed to authenticate using username/password \'" + 
             username + "\'/\'" + password + "\'."; 
       log.error(errorMessage); 
       throw new LifecycleException(errorMessage); 
      } 

      // perform the copy 
      sshClient.openScpClient().put(localFilePathName, remoteFilePathName, false); 
     } 
     catch (Exception ex) 
     { 
      // log the error and throw an exception 
      String errorMessage = "Failed to copy \'" + localFilePathName + "\' to \'" + remoteHost + ":" + 
            remoteFilePathName + "\'."; 
      log.error(errorMessage, ex); 
      throw new LifecycleException(errorMessage, ex); 
     } 
     finally 
     { 
      if ((sshClient != null) && sshClient.isConnected()) 
      { 
       sshClient.disconnect(); 
      } 
     } 
    } 

    /** 
    * Performs a secure copy of a single file (using scp). 
    * 
    * @param localFilePathName 
    * @param user 
    * @param password 
    * @param remoteHost 
    * @param remoteFilePathName 
    */ 
    @SuppressWarnings("unused") 
    private static void secureCopySingleFileJSch(final String localFilePathName, 
               final String user, 
               final String password, 
               final String remoteHost, 
               final String remoteFilePathName) 
    { 
     Session session = null; 
     Channel channel = null; 
     FileInputStream fileInputStream = null; 
     try 
     { 
      // create and connect Jsch session 
      JSch jsch = new JSch(); 
      session = jsch.getSession(user, remoteHost, 22); 
      session.setPassword(password); 
      session.connect(); 

      // exec 'scp -p -t remoteFilePathName' remotely 
      String command = "scp -p -t " + remoteFilePathName; 
      channel = session.openChannel("exec"); 
      ((ChannelExec) channel).setCommand(command); 

      // get the I/O streams for the remote scp 
      OutputStream outputStream = channel.getOutputStream(); 
      InputStream inputStream = channel.getInputStream(); 

      // connect the channel 
      channel.connect(); 

      int ackCheck = checkAck(inputStream); 
      if (checkAck(inputStream) != 0) 
      { 
       // log the error and throw an exception 
       String errorMessage = "The scp command failed -- input stream ACK check failed with the following result: " + 
             ackCheck; 
       log.error(errorMessage); 
       throw new LifecycleException(errorMessage); 
      } 

      // send "C0644 filesize filename", where filename should not include '/' 
      long filesize = (new File(localFilePathName)).length(); 
      command = "C0644 " + filesize + " "; 
      if (localFilePathName.lastIndexOf('/') > 0) 
      { 
       command += localFilePathName.substring(localFilePathName.lastInde 
+0

你究竟在哪里得到时间? ''process.waitFor();''??指定它。 – NawaMan 2009-10-02 17:10:05

回答

1

我已经放弃了为此使用ssh库的尝试,而是使用了一个简单的Runtime.exec()方法来发出ssh和scp命令。下面是我现在用它运作良好代码:

public static void executeSecureCommand(final String user, 
             final String remoteHost, 
             final String command) 
{ 
    // basic validation of the parameters 
    if ((user == null) || user.isEmpty()) 
    { 
     // log the error and throw an exception 
     String errorMessage = "Error executing the ssh command \'" + command + 
           "\': the supplied user name parameter is null or empty."; 
     log.error(errorMessage); 
     throw new LifecycleException(errorMessage); 
    } 
    if ((remoteHost == null) || remoteHost.isEmpty()) 
    { 
     // log the error and throw an exception 
     String errorMessage = "Error executing the ssh command \'" + command + 
           "\': the supplied remote host parameter is null or empty."; 
     log.error(errorMessage); 
     throw new LifecycleException(errorMessage); 
    } 
    if ((command == null) || command.isEmpty()) 
    { 
     // log the error and throw an exception 
     String errorMessage = "Error executing the ssh command: the supplied command parameter is null or empty."; 
     log.error(errorMessage); 
     throw new LifecycleException(errorMessage); 
    } 

    // create and execute a corresponding ssh command 
    String sshCommand = "ssh " + user + "@" + remoteHost + " " + command; 
    try 
    { 
     executeShellCommand(sshCommand); 
    } 
    catch (Exception ex) 
    { 
     // log the error and throw an exception 
     String errorMessage = "Error executing the secure shell command \'" + sshCommand + "\'"; 
     log.error(errorMessage, ex); 
     throw new LifecycleException(errorMessage, ex); 
    } 
} 

public static void executeSecureFileCopy(final String localFilePathName, 
             final String user, 
             final String remoteHost, 
             final String remoteFilePathName) 
{ 
    // basic validation of the parameters 
    if ((localFilePathName == null) || localFilePathName.isEmpty()) 
    { 
     // log the error and throw an exception 
     String errorMessage = "Error executing the secure copy -- the supplied local file path name parameter is null or empty."; 
     log.error(errorMessage); 
     throw new LifecycleException(errorMessage); 
    } 
    if ((user == null) || user.isEmpty()) 
    { 
     // log the error and throw an exception 
     String errorMessage = "Error executing the secure copy -- the supplied user name parameter is null or empty."; 
     log.error(errorMessage); 
     throw new LifecycleException(errorMessage); 
    } 
    if ((remoteHost == null) || remoteHost.isEmpty()) 
    { 
     // log the error and throw an exception 
     String errorMessage = "Error executing the secure copy -- the supplied remote host parameter is null or empty."; 
     log.error(errorMessage); 
     throw new LifecycleException(errorMessage); 
    } 
    if ((remoteFilePathName == null) || remoteFilePathName.isEmpty()) 
    { 
     // log the error and throw an exception 
     String errorMessage = "Error executing the secure copy -- the supplied remote file path name parameter is null or empty."; 
     log.error(errorMessage); 
     throw new LifecycleException(errorMessage); 
    } 

    try 
    { 
     // create an scp command we'll use to perform the secure file copy 
     String scpCommand = "scp -B -C -q " + localFilePathName + " " + user + "@" + remoteHost + ":" + 
          remoteFilePathName; 

     // execute the scp command 
     executeShellCommand(scpCommand); 
    } 
    catch (Exception ex) 
    { 
     // log the error and throw an exception 
     String errorMessage = "Failed to copy local file \'" + localFilePathName + "\' to remote host:file \'" + 
           remoteHost + ":" + remoteFilePathName + "\'."; 
     log.error(errorMessage, ex); 
     throw new LifecycleException(errorMessage, ex); 
    } 
} 

public static void executeShellCommand(final String command) 
{ 
    try 
    { 
     // create and execute a runtime process which runs the command 
     Process process = Runtime.getRuntime().exec(new String[] { "/bin/sh", "-c", command }); 

     // gobble the input stream 
     InputStream processInputStream = process.getInputStream(); 
     BufferedReader processInputStreamReader = new BufferedReader(new InputStreamReader(processInputStream)); 
     String inputStreamLine = processInputStreamReader.readLine(); 
     while (inputStreamLine != null) 
     { 
      inputStreamLine = processInputStreamReader.readLine(); 
     } 

     // capture the error stream 
     InputStream processErrorStream = process.getErrorStream(); 
     BufferedReader processErrorStreamReader = new BufferedReader(new InputStreamReader(processErrorStream)); 
     String errorStreamLine = processErrorStreamReader.readLine(); 
     StringBuffer errorBuffer = new StringBuffer(); 
     while (errorStreamLine != null) 
     { 
      errorBuffer.append(errorStreamLine); 
      errorStreamLine = processErrorStreamReader.readLine(); 
     } 

     // close the streams 
     processInputStream.close(); 
     processErrorStream.close(); 

     // wait for the process to finish and return the exit code 
     process.waitFor(); 
     if (process.exitValue() != 0) 
     { 
      // log the error and throw an exception 
      String errorMessage = "Failed to execute the shell command \'" + command + "\' -- Error: \'" + 
            errorBuffer.toString() + "\'"; 
      log.error(errorMessage); 
      throw new LifecycleException(errorMessage); 
     } 
    } 
    catch (Exception ex) 
    { 
     // log the error and throw an exception 
     String errorMessage = "Failed to execute the shell command \'" + command + "\'."; 
     log.error(errorMessage, ex); 
     throw new LifecycleException(errorMessage, ex); 
    } 
} 

如果有人看到问题与此代码,即可能出现的错误,我没有赶上,等等,那么请指出来。为了解决本文指出的所有问题(http://www.javaworld.com/javaworld/jw-12-2000/jw-1229-traps.html),我的原始代码相当复杂和复杂,但直到最近它才向我指出该文章已有近8年的历史了,而且它警告的许多问题不再适用于Java的当前版本。所以我回到了一个使用Runtime.exec()的基本解决方案,一切都很顺利。

再次感谢所有试图帮助我解决此问题的人。

2

如果使用jsch,而不是试图掏出你可能有更好的运气处理超时和错误。有用法示例here

在大多数情况下,您从JSch获得的错误在诊断这是连接问题还是逻辑问题时会更有帮助。

此外,不知道为什么你需要使用ls这种方式。您可以通过这种方式获得一组文件

File dir = new File("directory"); 
String[] children = dir.list(); 

不需要解析ls的输出。这将更便携。

+0

感谢您的回复,并提供了很好的建议。 – 2009-10-02 17:27:04

+0

我也有与jsch – 2009-10-02 20:03:49

+0

我得到使主机的连接时,出现以下异常好的经验: JSchException:算法协商失败 这发生在连接步骤: JSch jsch =新JSch(); session = jsch.getSession(user,remoteHost,22); session.setPassword(password); session.connect(); 任何人都可以评论什么可能是这个错误的原因? (顺便说一下,我也得到了我在连接步骤中使用j2ssh时出现的类似错误,IOException:socket是EOF) – 2009-10-06 03:48:35

0

这并不回答你的问题,但你可以尝试sshtools lib,很好地处理ssh。

一些示例:

SshClient ssh = = new SshClient(); 
ssh.connect(server, port, new IgnoreHostKeyVerification()); 
PasswordAuthenticationClient pwd = new PasswordAuthenticationClient(); 
pwd.setUsername(uid); 
pwd.setPassword(password); 
int result = ssh.authenticate(pwd); 
if (result == AuthenticationProtocolState.COMPLETE) { 
    SessionChannelClient session = ssh.openSessionChannel(); 
    session.executeCommand("sh test.sh"); 
} 
+0

使用此库进行连接时出现IOException: java.io.IOException:套接字是EOF 发生在connect()调用时: SshClient sshClient = new SshClient(); sshClient.setSocketTimeout(timeout); sshClient.connect(remoteHost,22); 任何人都可以评论这个例外是什么意思? – 2009-10-06 03:36:11

+0

我加了个快速的例子。再次不确定它是如何与您的问题相关的,对不起。 – serg 2009-10-06 05:49:48

+0

谢谢serg555。请参阅我的原始问题更新,其中列出了我用来制作ssh命令的代码。我的代码和上面演示的完全一样,除了我最初在连接步骤中没有使用IgnoreHostKeyVerification,但是现在我已经添加了该代码,但仍然无法正常执行,因此发生此错误时connect()调用失败:

严重:传输协议线程失败
java.io.IOException:套接字是EOF – 2009-10-06 22:44:44

0

我的猜测:什么用户Tomcat上运行的? SSH如何做密钥管理?我怀疑用户正在运行,因为没有正确配置密钥。

+0

谢谢,柔滑。我以root身份运行Tomcat。我不认为它真的很重要,因为在我的代码中,我得到了一个用户名和密码,并使用它们进行身份验证,而且我从来没有进入该步骤,因为代码在两个实现的connect()步骤中抛出了异常使用sshtools/j2ssh和jsch),它发生在认证步骤之前(参见我使用sshtools/j2ssh和jsch创建的两个实现的原始消息更新)。 – 2009-10-07 15:26:26