通过 PsExec 时程序输出丢失

2022-09-03 14:41:38

(这是我的同事在其他地方发布的一个问题,但我想我会把它贴在这里,看看我是否可以吸引不同的受众。

大家好,我正在测试编写一个小型java应用程序的可能性,该应用程序将使用Psexec来启动远程作业。在测试将java程序的stdin和stdout绑定到psexec的过程中,我遇到了一个奇怪的错误。

我的测试程序是一个基本的回声程序。它启动一个线程从 stdin 读取,然后将读取输出直接传送回 stdout。当在本地计算机上运行时,而不是从psexec运行时,它工作得很好。完全符合预期。

但是,当我第一次从 PsExec 调用它时,输入直接通过管道传输到 stdout 中时,它会丢失。使该 bug 真正令人眼花缭乱的是,只有在输入第一次直接通过管道传输到 stdout 时,它才会丢失。如果将输入字符串追加到另一个字符串,则工作正常。字符串文本或字符串变量。但是,如果输入字符串直接发送到 stdout,则不会通过。第二次它被发送到stdout时,它通过很好 - 每次之后。

我对这里发生的事情完全不知所措。我试图测试我能想到的每一个可能的错误。我没有想法。我错过了一个还是这只是psexec内部的东西?

这是有问题的代码,它有三个类(其中一个类实现了一个接口,该接口是单个函数 interace)。

主类:

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

CReader 类,它是从 stdin 读取的线程:

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

CEcho 类,它是将其管道传输回 stdout 的类:

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

最后,这是程序输出:

>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

答案 1

你有没有试过将输出重定向到一个文件( java...>c:\output.txt )?通过这种方式,您可以仔细检查是否所有内容都进入标准,也许只是被psexec吃掉


答案 2

PsExec正在吞噬输出。下一个有趣的事情可能是它在哪里吃掉输出。您可以通过获取Wireshark的副本并检查有问题的输出是否正在遍历网络来检查这一点。如果不是,那么它就在遥远的地方被吃掉了。如果是这样,它就是在当地吃的。

并不是说我真的确定从那里开始,但收集更多信息似乎是一条很好的路径......


推荐