首先,这是我的代码:
import java.io.*;
import java.util.Date;
import com.banctecmtl.ca.vlp.shared.exceptions.*;
public class PowershellTest implements Runnable {
public static final String PATH_TO_SCRIPT = "C:\\Scripts\\ScriptTest.ps1";
public static final String SERVER_IP = "XX.XX.XX.XXX";
public static final String MACHINE_TO_MOD = "MachineTest";
/**
* @param args
* @throws OperationException
*/
public static void main(String[] args) throws OperationException {
new PowershellTest().run();
}
public PowershellTest(){}
@Override
public synchronized void run() {
String input = "";
String error = "";
boolean isHanging = false;
try {
Runtime runtime = Runtime.getRuntime();
Process proc = runtime.exec("powershell -file " + PATH_TO_SCRIPT +" "+ SERVER_IP +" "+ MACHINE_TO_MOD);
proc.getOutputStream().close();
InputStream inputstream = proc.getInputStream();
InputStreamReader inputstreamreader = new InputStreamReader(inputstream);
BufferedReader bufferedreader = new BufferedReader(inputstreamreader);
proc.waitFor();
String line;
while (!isHanging && (line = bufferedreader.readLine()) != null) {
input += (line + "\n");
Date date = new Date();
while(!bufferedreader.ready()){
this.wait(1000);
//if its been more then 1 minute since a line has been read, its hanging.
if(new Date().getTime() - date.getTime() >= 60000){
isHanging = true;
break;
}
}
}
inputstream.close();
inputstream = proc.getErrorStream();
inputstreamreader = new InputStreamReader(inputstream);
bufferedreader = new BufferedReader(inputstreamreader);
isHanging = false;
while (!isHanging && (line = bufferedreader.readLine()) != null) {
error += (line + "\n");
Date date = new Date();
while(!bufferedreader.ready()){
this.wait(1000);
//if its been more then 1 minute since a line has been read, its hanging.
if(new Date().getTime() - date.getTime() >= 60000){
isHanging = true;
break;
}
}
}
inputstream.close();
proc.destroy();
} catch (IOException e) {
//throw new OperationException("File IO problem.", e);
} catch (InterruptedException e) {
//throw new OperationException("Script thread problem.",e);
}
System.out.println("Error : " + error + "\nInput : " + input);
}
}
我目前正在尝试运行一个 powershell 脚本,该脚本将在远程服务器上启动/停止虚拟机 (VMWARE)。该脚本通过命令行工作,此代码也是如此。问题是,我讨厌我必须使用线程(并让它等待脚本响应,如进一步解释的)来完成这样的工作。我必须这样做,因为 BufferedReader.readline() 和 proc.waitFor() 都永远挂起。
从 cmd 运行该脚本时,执行时间很长。从验证服务器身份验证到执行实际脚本,它会停滞 30 秒到 1 分钟。从我在调试中看到的情况来看,当 readline 开始从脚本接收这些延迟时,它会挂起。
我也很确定这不是内存问题,因为我在任何调试会话中都没有遇到任何 OOM 错误。
现在我明白 Process.waitFor() 要求我从错误流和常规流中刷新缓冲区才能工作,这就是我不使用它的主要原因(我需要输出来管理虚拟机特定错误、证书问题, ETC。)。
我想知道是否有人可以向我解释它为什么挂起,以及是否有一种方法可以只使用典型的 readline() 而不会让它挂得那么厉害。即使脚本应该已经结束一段时间了,它仍然挂起(我尝试使用与我在java应用程序中使用的完全相同的东西同时运行java应用程序和cmd命令,让它运行1小时,没有任何效果)。它不仅仅是被卡住了inwhile 循环中,readline() 是挂起的地方。
另外,这是一个测试版本,与最终代码相距甚远,所以请饶恕我:这应该是一个常量,这是无用的,等等。我稍后会清理代码。而且显然,我的代码中的 IP 不是 XX.XX.XX.XXX。
有关如何修复的解释或建议将不胜感激。
顺便说一句,这是我当前使用的脚本:
Add-PSSnapin vmware.vimautomation.core
Connect-VIServer -server $args[0]
Start-VM -VM "MachineTest"
如果您需要更多详细信息,我会尽力提供。
在此先感谢您的帮助!
编辑:我之前还使用要求不高的脚本测试了代码,该脚本的工作是获取文件的内容并打印它。由于无需等待即可获取信息,因此 readline() 运行良好。因此,我相当确定问题出在脚本执行的等待时间上。
另外,请原谅我的错误,英语不是我的主要语言。
在此先感谢您的帮助!
编辑2:因为我无法回答我自己的问题:
这是使用线程后我的“最终”代码:
import java.io.*;
public class PowershellTest implements Runnable {
public InputStream is;
public PowershellTest(InputStream newIs){
this.is = newIs;
}
@Override
public synchronized void run() {
String input = "";
String error = "";
try {
InputStreamReader inputstreamreader = new InputStreamReader(is);
BufferedReader bufferedreader = new BufferedReader(inputstreamreader);
String line;
while ((line = bufferedreader.readLine()) != null) {
input += (line + "\n");
}
is.close();
} catch (IOException e) {
//throw new OperationException("File IO problem.", e);
}
System.out.println("Error : " + error + "\nInput : " + input);
}
}
main 只需创建并启动 2 个线程(PowerShellTest 实例),其中 1 个用于 errorStream,1 个用于 inputStream。
我相信,当我第一次对应用程序进行编码时,我犯了一个愚蠢的错误,并在一遍又一遍地修改代码时以某种方式修复了它。它仍然需要 5-6 分钟才能运行,这在某种程度上是相似的,甚至比我之前的代码长(这是合乎逻辑的,因为在我的例子中 errorStream 和 inputStream 顺序获取它们的信息)。
不管怎样,感谢您的所有回答,特别是 Miserable Variable 对线程的提示。