O processo filho do Windows Java não entra ou sai quando definido como IO padrão do pai (Prompt de comando)

No Windows, não consigo manipular de forma confiável o E / S do meu processo filho quando meu programa foi iniciado a partir da linha de comando. É frustrante, pois é padrão para os servidores usarem um console para E / S. GUIs são legais, mas eu realmente prefiro manter a linha de comando e manter as coisas simples. Eu notei que a E / S do processo filho está bem quando estou executando meu servidor a partir do Eclipse IDE, mas é uma história completamente diferente sendo executada a partir da linha de comando. Não consigo ler ou escrever no processo filho, mas o processo ainda estaria em execução. Eu escrevi algum código de teste abaixo que demonstra esse problema, e espero que o problema possa ser reproduzido em outra máquina e esperamos obter uma solução dele. Quando executado a partir do Eclipse, a E / S herdada funciona conforme o esperado. No entanto, quando executado a partir do prompt de comando do Windows, nada pode ser lido ou gravado no processo filho. Em ambos os casos, o redirecionamento da saída do processo filho para um arquivo sempre é bem-sucedido, mas a entrada ainda não pode ser passada para o filho. Se já houver uma solução para este problema, por favor, vincule a página.

Implementação do JRE / JDK:

>java -version
java version "1.7.0_01"
Java(TM) SE Runtime Environment (build 1.7.0_01-b08)
Java HotSpot(TM) 64-Bit Server VM (build 21.1-b02, mixed mode)

Considere o seguinte código:

package com.comp8nerd4u2.io.test;

/*
 * These tests attempt to confirm what I'm experiencing under my build environment
 */

import java.io.File;
import java.io.IOException;

public final class PIOTest {

/** The command to run as a child process. The command itself isn't the test, but what you use to run this Java program is the test. */
private static final String[] COMMAND = {"cmd.exe", "/c", "echo This is a test. Feel free to change this."}; // Change this to just {"cmd.exe"} or some other program that accepts input and you'll see how frustrating this is
/** Controls how the test process is built */
private static final ProcessBuilder PB = new ProcessBuilder(COMMAND);
/** How long to allow the process to run before forcibly terminating it. */
private static final long PROCESS_TIMEOUT = 10000L;
private static final Runnable R = new TimedInterruptWorker(PROCESS_TIMEOUT);

private static int n = 0;

static {
    PB.redirectErrorStream(true);
}

private PIOTest() {}

public static void main(String[] args) {

    // ----- Begin Tests -----

    /*
     * Test #1: Let's test putting our command's output onto our standard I/O streams
     * Goal condition: Child process outputs expected output, and exits before the timeout. If child process expects input, it should accept entered input.
     * Known success factors: Parent process' standard I/O is piped to Eclipse. Tests would probably succeed with Netbeans as well
     * Known fail factors: Parent process' standard I/O is piped to Windows Command Prompt
     * Result under fail condition: Child process hangs if it fills up its output buffer or requests input, but exits on its own otherwise, unless it took longer than the timeout. 
     */
    PB.inheritIO();
    doTest();

    // Test #2: Let's test putting our command's output into a file
    PB.redirectOutput(new File("piotest.txt"));
    doTest();
}

/**
 * Performs the I/O test.
 */
private static void doTest() {
    n++;
    Process p = null;
    try {
        p = PB.start();
    } catch (IOException e) {
        e.printStackTrace();
        return;
    }
    try {
        Thread t = new Thread(R);
        t.setDaemon(true);
        t.start();
        System.out.format("[Test #%d] Child exited with status code %d\n", n, p.waitFor());
        t.interrupt();
    } catch (InterruptedException e) {
        p.destroy();
        System.out.format("[Test #%d] Child took longer than the timeout.\n", n);
    }
}

/**
 * Useful for sending interrupts after a certain amount of time has passed.
 * 
 * @author comp8nerd4u2
 */
private static final class TimedInterruptWorker implements Runnable {

    private long timeout = 0;
    private Thread target = null;

    public TimedInterruptWorker(long timeout) {
        this(timeout, Thread.currentThread());
    }

    public TimedInterruptWorker(long timeout, Thread target) {
        this.timeout = timeout;
        this.target = target;
    }

    @Override
    public void run() {
        try {
            Thread.sleep(timeout);
        } catch (InterruptedException e) {
            return;
        }
        target.interrupt();
    }

}

}

ATUALIZAÇÃO: Eu modifiquei o teste para aceitar qualquer comando em tempo de execução, e enviei para o meu servidor vps linux. Eu executei-o a partir de uma sessão ssh e todos os processos filhos de E / S podem ser lidos e gravados com facilidade. Houve uma coisa que eu notei. Quando eu abri um shell bash interativo como um processo filho, e então redireciono sua saída para um arquivo, o CentOS parou meu programa, eu acho. Isso ou meu programa caiu.

[admin@comp8nerd4u2 piotest]$ java -jar piotest.jar
Enter command to run : bash
[admin@comp8nerd4u2 piotest]$ [Test #1] Child took longer than the timeout.

[1]+  Stopped                 java -jar piotest.jar
[admin@comp8nerd4u2 piotest]$

A primeira linha é minha digitação no comando. A segunda linha é o shell bash que foi gerado, mas eu nunca digitei nada nele, então meu programa o mata após o tempo limite. Ele fica pronto para o segundo teste, cria o arquivo "piotest.txt" e, em seguida, trava ou é interrompido pelo sistema operacional. O teste real em si não foi alterado, exceto que o teste agora permite inserir o comando a ser executado no tempo de execução. Isso funciona bem no linux, mas não no Windows. Espero que alguém que conheça a API do Win32 possa de alguma forma explicar por que esse teste falha no Windows.

questionAnswers(2)

yourAnswerToTheQuestion