从我的 Java 程序执行 ssh 命令时超时
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1510759/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Timeout when ssh command is executed from my Java program
提问by James Adams
I have a Java program which runs in Tomcat and which needs to execute several ssh and scp commands, as well as a few simple commands such as ls on the local machine. I am having trouble with my current approach in that I am getting a time out every time I execute an ssh command. I can run the ssh command on the command line with no problems, but when it's executed from my Java program it times out. I am running the web application in which the ssh commands are executed as root (i.e. I start Tomcat as root user, with my web application code deployed as a WAR file), and as far as I know the correct certification keys are configured on both the local and remote machines, at least I can perform the ssh commands at command line as root without having to enter a user name or password. I do not specify the user name or password in the ssh command that is being executed by my Java program since I assume that I can run the same ssh command in my Java code as I can execute at command line, but maybe this is a false assumption and is the cause of my trouble.
我有一个 Java 程序,它在 Tomcat 中运行,它需要在本地机器上执行几个 ssh 和 scp 命令,以及一些简单的命令,例如 ls。我目前的方法有问题,因为每次执行 ssh 命令时我都会超时。我可以毫无问题地在命令行上运行 ssh 命令,但是当它从我的 Java 程序中执行时它会超时。我正在运行以 root 身份执行 ssh 命令的 Web 应用程序(即,我以 root 用户身份启动 Tomcat,并将我的 Web 应用程序代码部署为 WAR 文件),据我所知,两者都配置了正确的认证密钥本地和远程机器,至少我可以在命令行中以 root 身份执行 ssh 命令,而无需输入用户名或密码。
The Java code I have developed to perform command execution is as follows:
我开发的用于执行命令的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;
}
}
I execute the ssh commands in my Java program like so:
我在我的 Java 程序中执行 ssh 命令,如下所示:
ProcessUtility.executeCommand("ssh " + physicalHostIpAddress + " virsh list \| grep " + newDomUName, false, false, 3600000)
ProcessUtility.executeCommand("ssh" + physicalHostIpAddress + " virsh list \| grep " + newDomUName, false, false, 3600000)
Can anyone see what I am doing wrong? BTW the above code was developed using this article as a guide: http://www.javaworld.com/javaworld/jw-12-2000/jw-1229-traps.html. I am not very expert with concurrent programming so perhaps I am doing something boneheaded -- feel free to point it out if so.
谁能看到我做错了什么?顺便说一句,上述代码是使用本文作为指南开发的:http: //www.javaworld.com/javaworld/jw-12-2000/jw-1229-traps.html。我不是并发编程的专家,所以也许我正在做一些愚蠢的事情——如果是这样,请随时指出。
Thanks a lot in advance for any suggestions, ideas, etc.
非常感谢您提供任何建议、想法等。
--James
- 詹姆士
Update: I have now taken the advice of the helpful folks who responded to my original question and have written a class which provides methods for making ssh and scp calls, implemented using two Java ssh libraries jsch (jsch-0.1.31) and sshtools (j2ssh-core-0.2.9). However neither of these implementations are working in that they are both failing at the connect step, before I even get the chance to perform authentication. I expect that I am facing some sort of configuration issue on the servers where I am running the codes, although this is not obvious since I can perform ssh and scp commands on these servers with no problems when I issue the ssh or scp commands on the command line. The Solaris servers that I am testing my code on are showing the following as a result of ssh -V:
更新:我现在听取了回答我最初问题的乐于助人的建议,并编写了一个类,该类提供了进行 ssh 和 scp 调用的方法,使用两个 Java ssh 库 jsch (jsch-0.1.31) 和 sshtools ( j2ssh-core-0.2.9)。然而,这些实现都没有工作,因为它们都在连接步骤失败,在我什至有机会执行身份验证之前。我希望我在运行代码的服务器上面临某种配置问题,尽管这并不明显,因为当我在这些服务器上发出 ssh 或 scp 命令时,我可以毫无问题地在这些服务器上执行 ssh 和 scp 命令命令行。作为 ssh -V 的结果,我正在测试我的代码的 Solaris 服务器显示以下内容:
Sun_SSH_1.3, SSH protocols 1.5/2.0, OpenSSL 0x0090801f
Sun_SSH_1.3,SSH 协议 1.5/2.0,OpenSSL 0x0090801f
Below is the Java code I have written for this purpose -- if anyone can see what I am doing wrong at the Java code level then please let me know, and if so thanks a lot in advance for your help.
下面是我为此目的编写的 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
采纳答案by James Adams
I have abandoned my attempts at using ssh libraries for this and have instead used a bare-bones Runtime.exec() approach for issuing ssh and scp commands. Here's the code that I'm now using which is working well:
我已经放弃了为此使用 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);
}
}
If anyone sees issues with this code, i.e. possible errors I'm not catching, etc. then please point them out. My original code was quite complicated and convoluted in order to address all of the issues pointed out in this article (http://www.javaworld.com/javaworld/jw-12-2000/jw-1229-traps.html) but only recently was it pointed out to me that that article is almost 8 years old and that many of the issues it warns about are no longer applicable in current releases of Java. So I'm back to a basic solution which uses Runtime.exec() and all seems well.
如果有人看到此代码的问题,即我没有发现的可能错误等,请指出它们。为了解决本文中指出的所有问题(http://www.javaworld.com/javaworld/jw-12-2000/jw-1229-traps.html),我的原始代码非常复杂和令人费解,但仅最近有人向我指出那篇文章已经有将近 8 年的历史了,并且它警告的许多问题在当前的 Java 版本中不再适用。所以我回到了一个使用 Runtime.exec() 的基本解决方案,一切看起来都很好。
Thanks again to everyone who tried to help me solve this problem.
再次感谢所有试图帮助我解决这个问题的人。
回答by sal
You might have better luck dealing with timeout and errors if you use jschrather than try to shell out. There are usage examples here.
如果您使用jsch而不是尝试掏空,您可能会在处理超时和错误方面有更好的运气。有使用的例子在这里。
In most cases, the errors you'll get from JSch will be much more helpful in diagnosing if this is a connection issue or a logic problem.
在大多数情况下,您从 JSch 得到的错误将有助于诊断这是连接问题还是逻辑问题。
Also, not sure why you need to use lsthis way. You can get an array of files this way
另外,不确定为什么需要使用ls这种方式。您可以通过这种方式获取一组文件
File dir = new File("directory");
String[] children = dir.list();
Without having to parse the output of ls. This will be much more portable.
无需解析ls. 这将更加便携。
回答by serg
This doesn't answer your question, but you can try sshtoolslib that handles ssh nicely.
这不能回答您的问题,但您可以尝试很好地处理 ssh 的sshtoolslib。
Some example:
一些例子:
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");
}
回答by Noon Silk
My guess: What user is tomcat running as? And how does SSH do key-management? I suspect the user that it's running as doesn't have proper keys configured.
我的猜测:tomcat 以什么用户身份运行?SSH 如何进行密钥管理?我怀疑正在运行的用户没有配置正确的密钥。

