从我的Java程序执行ssh命令时超时

时间:2009-10-02 17:04:59

标签: java process ssh runtime command

我有一个在Tomcat中运行的Java程序,它需要执行几个ssh和scp命令,以及一些简单的命令,例如本地机器上的ls。我在使用当前的方法时遇到问题,因为每次执行ssh命令时都会有时间。我可以在命令行上运行ssh命令没有问题,但是当它从我的Java程序执行时它会超时。我正在运行以root身份执行ssh命令的web应用程序(即我以root用户身份启动Tomcat,将我的Web应用程序代码部署为WAR文件),据我所知,两者都配置了正确的证书密钥本地和远程机器,至少我可以在命令行以root身份执行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

4 个答案:

答案 0 :(得分:2)

如果您使用jsch而不是尝试炮轰,那么处理超时和错误可能会更好。有一些用法示例here

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

另外,不确定为什么需要以这种方式使用ls。您可以通过这种方式获取文件数组

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

无需解析ls的输出。这将更加便携。

答案 1 :(得分: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 :(得分: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");
}

答案 3 :(得分:0)

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