2013-02-07 14 views
9

Używam libuv. Przeczytałem http://nikhilm.github.com/uvbook/processes.html i nadal nie mogę dowiedzieć się, jak przechwycić stdout procesu potomnego, aby był dostępny w rodzicu (ale nie w miejscu stdin rodzica).Przechwyć standardowe wyjście procesu z libuv

Moje kod jest obecnie:

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

Mam dręczące poczucie, że ja nie bardzo rozumiem punkt rur libuv jest jeszcze.

Odpowiedz

5

Znalazłem rozwiązanie:

  1. miałem złych emocji, powinny one być UV_CREATE_PIPE | UV_READABLE_PIPE nie UV_INHERIT_STREAM.
  2. Musiałem zadzwonić pod numer uv_read_start po uv_spawn. Zakładam, że nie ma szans na utratę danych, ponieważ uv_run nie został jeszcze wywołany.
  3. Powyższe dwie poprawki pokazały, że wszystkie dane wyjściowe z dummy są wysyłane natychmiast, a nie w trzech bryłach (tak jak w wierszu poleceń). Naprawiono to w fflush w dummy.c.

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

Zobacz, jak robią to w badanej jednostki libuv libuv/test/test-stdio-over-pipes.c:

  • Nie nazywaj uv_pipe_open
  • Flagi dla standardowego wejścia dziecka: UV_CREATE_PIPE | UV_READABLE_PIPE
  • Flagi na standardowe wyjście dziecka i stderr: UV_CREATE_PIPE | UV_WRITABLE_PIPE

Istnieje również issue na Windows, gdzie uv_spawn może powrócić do zera, mimo że wystąpił błąd, a w tych przypadkach, Państwo należy sprawdzić process.spawn_error, który istnieje tylko w systemie Windows.

Powiązane problemy