Die Programmausgabe geht verloren, wenn sie PsExec durchläuft

(Dies ist eine Frage, die mein Kollege gepostet hatanderswo, aber ich dachte, ich würde es hier posten, um zu sehen, ob ich ein anderes Publikum erreichen könnte.)

Hallo zusammen, ich teste die Möglichkeit, eine kleine Java-Anwendung zu schreiben, die Psexec verwendet, um Remote-Jobs zu starten. Beim Testen der Bindung von stdin und stdout eines Java-Programms an psexec bin ich auf einen seltsamen Fehler gestoßen.

Mein Testprogramm ist ein grundlegendes Echoprogramm. Es startet einen Thread zum Lesen von stdin und leitet die gelesene Ausgabe direkt zurück an stdout. Wenn es auf dem lokalen Rechner läuft, nicht von psexec, funktioniert es wunderbar. Genau so, wie es sein sollte.

Wenn ich es jedoch das erste Mal von PsExec aus aufrufe, wenn die Eingabe direkt in stdout geleitet wird, geht sie verloren. Was den Fehler wirklich verblüffend macht, ist, dass er nur dann verloren geht, wenn die Eingabe zum ersten Mal direkt in stdout geleitet wird. Wenn die Eingabezeichenfolge an eine andere Zeichenfolge angehängt wird, funktioniert sie einwandfrei. Entweder ein String-Literal oder eine String-Variable. Wenn die Eingabezeichenfolge jedoch direkt an stdout gesendet wird, wird sie nicht durchlaufen. Das zweite Mal, wenn es an stdout gesendet wird, geht es gut durch - und jedes Mal, wenn es danach kommt.

Ich bin völlig ratlos, was hier los ist. Ich habe versucht, auf jeden möglichen Fehler zu testen, der mir einfällt. Ich habe keine Ideen mehr. Habe ich einen verpasst oder ist das nur etwas in psexec?

Hier ist der fragliche Code, es ist in drei Klassen (von denen eine eine Schnittstelle implementiert, die eine einzelne Funktionsschnittstelle ist).

Die Hauptklasse:

public class Main {
    public static void main(String[] args) {
        System.out.println("Starting up.");

        CReader input = new CReader(new BufferedReader(
            new InputStreamReader(System.in)));
        CEcho echo = new CEcho();

        input.addInputStreamListener(echo);
        input.start();

        System.out.println("Successfully started up.  Awaiting input.");
    }
}

Die CReader-Klasse, die den Thread darstellt, der aus stdin liest:

public class CReader extends Thread {
    private ArrayList<InputStreamListener> listeners = 
        new ArrayList<InputStreamListener>();
    private boolean exit = false;
    private Reader in;

    public CReader(Reader in) {
        this.in = in;
    }

    public void addInputStreamListener(InputStreamListener listener) {
        listeners.add(listener);
    }

    public void fireInputRecieved(String input) {

        if(input.equals("quit"))
        exit = true;

        System.out.println("Input string has made it to fireInputRecieved: "
            + input);

        for(int index = 0; index < listeners.size(); index++)
            listeners.get(index).inputRecieved(input);
    }

    @Override
    public void run() {

        StringBuilder sb = new StringBuilder();
        int current = 0, last = 0;

        while (!exit) {
            try {
                current = in.read();
            }
            catch (IOException e) {
                System.out.println("Encountered IOException.");
            }

            if (current == -1) {
                break;
            }

            else if (current == (int) '\r') {
                if(sb.toString().length() == 0) {
                    // Extra \r, don't return empty string.
                    continue;
                }
                fireInputRecieved(new String(sb.toString()));
                sb = new StringBuilder();
            }

            else if(current == (int) '\n') {
                if(sb.toString().length() == 0) {
                    // Extra \n, don't return empty string.
                    continue;
                }
                fireInputRecieved(new String(sb.toString()));
                sb = new StringBuilder();
            }
            else {
                System.out.println("Recieved character: " + (char)current);
                sb.append((char) current);
                last = current;
            }
        }       
    }
}

Die CEcho-Klasse, dh die Klasse, die sie an stdout zurückleitet:

public class CEcho implements InputStreamListener {
    public void inputRecieved(String input) {
        System.out.println("\n\nSTART INPUT RECIEVED");
        System.out.println("The input that has been recieved is: "+input);
        System.out.println("It is a String, that has been copied from a " +
            "StringBuilder's toString().");
        System.out.println("Outputting it cleanly to standard out: ");
        System.out.println(input);
        System.out.println("Outputting it cleanly to standard out again: ");
        System.out.println(input);
        System.out.println("Finished example outputs of input: "+input);
        System.out.println("END INPUT RECIEVED\n\n");
    }
}

Und zum Schluss hier die Programmausgabe:

>psexec \\remotecomputer "C:\Program Files\Java\jre1.6.0_05\bin\java.exe" -jar "C:\Documents and Settings\testProram.jar"

PsExec v1.96 - Execute processes remotely
Copyright (C) 2001-2009 Mark Russinovich
Sysinternals - www.sysinternals.com


Starting up.
Successfully started up.  Awaiting input.
Test
Recieved character: T
Recieved character: e
Recieved character: s
Recieved character: t
Input string has made it to fireInputRecieved: Test


START INPUT RECIEVED
The input that has been recieved is: Test
It is a String, that has been copied from a StringBuilder's toString().
Outputting it cleanly to standard out:

Outputting it cleanly to standard out again:
Test
Finished example outputs of input: Test
END INPUT RECIEVED

Antworten auf die Frage(13)

Ihre Antwort auf die Frage