2013-02-07 26 views
9

Sto usando libuv. Ho letto http://nikhilm.github.com/uvbook/processes.html e ancora non riesco a capire come acquisire lo stdout di un processo figlio in modo che sia disponibile nel genitore (ma non al posto dello stdin del genitore).Catturare lo stdout di un processo figlio con libuv

Il mio codice è attualmente:

#include <stdio.h> 
#include <stdlib.h> 
#include "../../libuv/include/uv.h" 

uv_loop_t *loop; 
uv_process_t child_req; 
uv_process_options_t options; 
uv_pipe_t apipe; 

void on_child_exit(uv_process_t *req, int exit_status, int term_signal) { 
    fprintf(stderr, "Process exited with status %d, signal %d\n", exit_status, term_signal); 
    uv_close((uv_handle_t*) req, NULL); 
} 

uv_buf_t alloc_buffer(uv_handle_t *handle, size_t len) { 
    printf("alloc_buffer called\n"); 
    uv_buf_t buf; 
    buf.base = malloc(len); 
    buf.len = len; 
    return buf; 
} 

void read_apipe(uv_stream_t* stream, ssize_t nread, uv_buf_t buf) { 
    printf("read %li bytes from the child process\n", nread); 
} 

int main(int argc, char *argv[]) { 
    printf("spawn_test\n"); 
    loop = uv_default_loop(); 

    char* args[3]; 
    args[0] = "dummy"; 
    args[1] = NULL; 
    args[2] = NULL; 

    uv_pipe_init(loop, &apipe, 0); 
    uv_pipe_open(&apipe, 0); 

    options.stdio_count = 3; 
    uv_stdio_container_t child_stdio[3]; 
    child_stdio[0].flags = UV_IGNORE; 
    child_stdio[1].flags = UV_INHERIT_STREAM; 
    child_stdio[1].data.stream = (uv_stream_t *) &apipe; 
    child_stdio[2].flags = UV_IGNORE; 
    options.stdio = child_stdio; 

    options.exit_cb = on_child_exit; 
    options.file = args[0]; 
    options.args = args; 

    uv_read_start((uv_stream_t*)&apipe, alloc_buffer, read_apipe); 
    if (uv_spawn(loop, &child_req, options)) { 
     fprintf(stderr, "%s\n", uv_strerror(uv_last_error(loop))); 
     return 1; 
    } 

    return uv_run(loop, UV_RUN_DEFAULT); 
} 

dummy.c:

#include <unistd.h> 
#include <stdio.h> 

int main() { 
    printf("child starting\n"); 
    sleep(1); 
    printf("child running\n"); 
    sleep(2); 
    printf("child ending\n"); 
    return 0; 
} 

ho la fastidiosa sensazione che io non capisco il punto di tubi di libuv ancora.

risposta

5

ho trovato la soluzione:

  1. ho avuto le bandiere sbagliate, avrebbero dovuto essere UV_CREATE_PIPE | UV_READABLE_PIPE non UV_INHERIT_STREAM.
  2. Avevo bisogno di chiamare uv_read_start dopo uv_spawn. Suppongo che non ci siano possibilità di perdita di dati, dato che uv_run non è stato ancora chiamato.
  3. Quanto sopra due correzioni mostrato tutto l'output dummy di arrivare in una volta, piuttosto che in tre grumi (come fa sulla linea di comando). Un fflush in dummy.c risolto questo.

spawn_test:

#include <stdio.h> 
#include <stdlib.h> 
#include "../../libuv/include/uv.h" 

uv_loop_t *loop; 
uv_process_t child_req; 
uv_process_options_t options; 
uv_pipe_t apipe; 

void on_child_exit(uv_process_t *req, int exit_status, int term_signal) { 
    fprintf(stderr, "Process exited with status %d, signal %d\n", exit_status, term_signal); 
    uv_close((uv_handle_t*) req, NULL); 
} 

uv_buf_t alloc_buffer(uv_handle_t *handle, size_t len) { 
    printf("alloc_buffer called, requesting a %lu byte buffer\n"); 
    uv_buf_t buf; 
    buf.base = malloc(len); 
    buf.len = len; 
    return buf; 
} 

void read_apipe(uv_stream_t* stream, ssize_t nread, uv_buf_t buf) { 
    printf("read %li bytes in a %lu byte buffer\n", nread, buf.len); 
    if (nread + 1 > buf.len) return; 
    buf.base[nread] = '\0'; // turn it into a cstring 
    printf("read: |%s|", buf.base); 
} 

int main(int argc, char *argv[]) { 
    printf("spawn_test\n"); 
    loop = uv_default_loop(); 

    char* args[3]; 
    args[0] = "dummy"; 
    args[1] = NULL; 
    args[2] = NULL; 

    uv_pipe_init(loop, &apipe, 0); 
    uv_pipe_open(&apipe, 0); 

    options.stdio_count = 3; 
    uv_stdio_container_t child_stdio[3]; 
    child_stdio[0].flags = UV_IGNORE; 
    child_stdio[1].flags = UV_CREATE_PIPE | UV_READABLE_PIPE; 
    child_stdio[1].data.stream = (uv_stream_t *) &apipe; 
    child_stdio[2].flags = UV_IGNORE; 
    options.stdio = child_stdio; 

    options.exit_cb = on_child_exit; 
    options.file = args[0]; 
    options.args = args; 

    if (uv_spawn(loop, &child_req, options)) { 
     fprintf(stderr, "%s\n", uv_strerror(uv_last_error(loop))); 
     return 1; 
    } 
    uv_read_start((uv_stream_t*)&apipe, alloc_buffer, read_apipe); 

    return uv_run(loop, UV_RUN_DEFAULT); 
} 

dummy.c:

#include <unistd.h> 
#include <stdio.h> 

int main() { 
    printf("child starting\n"); 
    fflush(stdout); 
    sleep(1); 
    printf("child running\n"); 
    fflush(stdout); 
    sleep(2); 
    printf("child ending\n"); 
    fflush(stdout); 
    return 0; 
} 
4

Vedi come lo fanno nel libuv unit test libuv/test/test-stdio-over-pipes.c:

  • non chiamano uv_pipe_open
  • Bandiere per stdin del bambino: UV_CREATE_PIPE | UV_READABLE_PIPE
  • Bandiere per stdout del bambino e stderr: UV_CREATE_PIPE | UV_WRITABLE_PIPE

C'è anche un issue su Windows, dove uv_spawn potrebbe restituire zero, anche se ha rilevato un errore, e in quei casi, è è necessario controllare process.spawn_error, che esiste solo su Windows.

Problemi correlati