El proceso hijo de Windows Java no ingresa ni se genera cuando se configura en el IO estándar de los padres

Bajo Windows, no puedo manipular de manera confiable la E / S del proceso hijo cuando mi programa se inició desde la línea de comandos. Es frustrante, ya que es estándar que los servidores usen una consola para E / S. Las GUI son agradables, pero realmente prefiero atenerme a la línea de comandos y mantener las cosas simples. Me he dado cuenta de que la E / S de proceso hijo está bien cuando ejecuto mi servidor desde el IDE de Eclipse, pero es una historia completamente diferente que se ejecuta desde la línea de comandos. No puedo leer ni escribir en el proceso hijo, pero el proceso todavía se está ejecutando. A continuación, he escrito un código de prueba que demuestra este problema, y ​​espero que el problema pueda reproducirse en otra máquina y, con suerte, obtener una solución. Cuando se ejecuta desde Eclipse, la E / S heredada funciona como se esperaba. Sin embargo, cuando se ejecuta desde el símbolo del sistema de Windows, no se puede leer ni escribir nada en el proceso secundario. En ambos casos, la redirección de la salida del proceso hijo a un archivo siempre tiene éxito, pero la entrada aún no se puede pasar al hijo. Si ya existe una solución a este problema, por favor vincule la página.

Implementación 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 el siguiente 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();
    }

}

}

ACTUALIZACIÓN: modifiqué la prueba para aceptar cualquier comando en tiempo de ejecución y la subí a mi servidor linux vps. Lo ejecuté desde una sesión ssh y todos los procesos secundarios de E / S se pueden leer y escribir con facilidad. Había una cosa que he notado. Cuando abrí una shell de bash interactiva como un proceso secundario, y luego redirigir su salida a un archivo, CentOS detuvo mi programa, creo. Eso o mi programa se estrelló.

[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]$

La primera línea es mi escritura en el comando. La segunda línea es el shell bash que se generó, pero nunca escribí nada en él, por lo que mi programa lo mata después del tiempo de espera. Se prepara para la segunda prueba, crea el archivo "piotest.txt" y luego se bloquea o es detenido por el sistema operativo. La prueba real en sí no se modificó, excepto que la prueba ahora le permite ingresar qué comando ejecutar en tiempo de ejecución. Esto funciona bien en Linux, pero no en Windows. Espero que alguien que conozca la API de Win32 pueda explicar de alguna manera por qué esta prueba falla en Windows.

Respuestas a la pregunta(2)

Su respuesta a la pregunta