3

まず、これは私のコードです:

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);
}

}

現在、リモートサーバーでvm(VMWARE)を開始/停止するPowerShellスクリプトを実行しようとしています。スクリプトはコマンドラインから機能するため、このコードも機能します。問題は、そのようなジョブにスレッドを使用する方法(および、さらに説明するように、スクリプトが応答するのを待機させる方法)が嫌いなことです。BufferedReader.readline()とproc.waitFor()の両方が永久にハングするため、私はそれをしなければなりませんでした。

スクリプトをcmdから実行すると、実行に時間がかかります。サーバーで認証を検証して実際のスクリプトを実行してから30秒から1分間停止します。デバッグから見たところ、スクリプトからこれらの遅延を受け取り始めると、readlineがハングします。

また、デバッグセッションでOOMエラーが発生したことは一度もないので、メモリの問題ではないと確信しています。

Process.waitFor()を使用するには、エラーストリームと通常のストリームの両方からバッファをフラッシュする必要があることを理解しました。そのため、主にそれを使用しません(VM固有のエラー、証明書の問題を管理するための出力が必要です) 、など)。

なぜハングするのか、そして通常のreadline()をそれほど強くハングさせることなく使用する方法があるかどうか、誰かが私に説明できるかどうかを知りたいです。スクリプトがしばらくして終了したとしても、ハングします(Javaアプリケーションで使用しているものとまったく同じものを同時に使用してJavaアプリケーションとcmdコマンドの両方を実行しようとしましたが、1時間実行したままにすると、何も機能しませんでした)。それはwhileループで立ち往生ているだけでなく、readline()がぶら下がっている場所です。

また、これはテストバージョンであり、最終的なコードにはほど遠いので、私を惜しまないでください。これは定数である必要があり、これは役に立たないなどです。後でコードをクリーンアップします。また、私のコードでは、IPは明らかにXX.XX.XX.XXXではありません。

修正方法の説明または提案をいただければ幸いです。

ここに私が現在使用しているスクリプトがあります:

Add-PSSnapin vmware.vimautomation.core

Connect-VIServer -server $args[0]

Start-VM -VM "MachineTest"

あなたがより多くの詳細を必要とするならば、私は私ができる限り多くを与えるように努めます。

よろしくお願いします!

編集:私は以前、ファイルの内容を取得して印刷するという、それほど要求の厳しいスクリプトを使用してコードをテストしました。情報を取得するのに待つ必要がなかったので、readline()はうまく機能しました。したがって、問題はスクリプトの実行による待機時間にあると確信しています。

また、私の間違いを許してください、英語は私の主な言語ではありません。

よろしくお願いします!

EDIT2:私は自分の質問に答えることができないので:

スレッドを使用した後の私の「最終的な」コードは次のとおりです。

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);
}

}

そして、メインは2つのスレッド(PowerShellTestインスタンス)を作成して開始します。1つはerrorStreamで、もう1つはinputStreamで開始します。

私が最初にアプリをコーディングしたときにばかげたエラーを犯し、コードを何度も作り直したときになんとかして修正したと思います。実行にはまだ5〜6分かかります。これは、以前のコードより長くない場合でも、なんとなく似ています(私の場合、errorStreamとinputStreamが情報を順番に取得するため、これは論理的です)。

とにかく、あなたのすべての答え、そして特にスレッドに関する彼のヒントをくれたMiserableVariableに感謝します。

4

2 に答える 2

5

waitFor()まず、ストリームを読み終えるまで電話をかけないでください。ProcessBuilder単にを使用するのではなく、見Runtime.execて、Javaに依存するのではなく、コマンドを自分で分割することを強くお勧めします。

ProcessBuilder pb = new ProcessBuilder("powershell", "-file", PATH_TO_SCRIPT,
        SERVER_IP, MACHINE_TO_MOD);
pb.redirectErrorStream(true); // merge stdout and stderr
Process proc = pb.start();

redirectErrorStreamエラー出力を通常の出力にマージするため、を読み取るだけで済みますproc.getInputStream()その後、EOFまでそのストリームを読み取ってから、を呼び出すことができるはずですproc.waitFor()

于 2012-10-09T20:19:42.063 に答える
4

inputStream現在、からの読み取りを開始する前に、からの読み取りが完了するのを待っていerrorStreamます。stderrプロセスが以前に書き込みを行った場合stdout、デッドロック状態に陥っている可能性があります。

同時に実行されているスレッドから両方のストリームから読み取ってみてください。そこにいる間に、も削除しproc.getOutputStream().close();ます。動作に影響を与えることはありませんが、必須ではありません。

于 2012-10-09T20:42:28.473 に答える