2013-02-07 60 views
9

我正在使用libuv。我讀過http://nikhilm.github.com/uvbook/processes.html,但仍無法確定如何捕獲子進程的stdout,以便它可在父進程中使用(但不能代替父進程的stdin)。使用libuv捕獲子進程的stdout

我的代碼是目前:

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

我嘮叨的感覺,我不太明白libuv的管道尚未點。

回答

5

我已經找到了解決辦法:

  1. 我有錯誤的標誌,他們應該已經UV_CREATE_PIPE | UV_READABLE_PIPE沒有UV_INHERIT_STREAM
  2. 我需要在uv_spawn之後致電uv_read_start。我認爲沒有數據丟失的機會,因爲uv_run尚未被調用。
  3. 以上兩個修復程序顯示dummy的所有輸出都是一次到達的,而不是三個塊(就像它在命令行中一樣)。 中的fflush解決了這個問題。

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

看看他們是如何做到這一點的libuv單元測試libuv/test/test-stdio-over-pipes.c

  • 不要叫uv_pipe_open
  • 個標誌爲孩子的標準輸入:UV_CREATE_PIPE | UV_READABLE_PIPE
  • 標誌爲孩子的輸出和錯誤:UV_CREATE_PIPE | UV_WRITABLE_PIPE

也有在Windows上,其中uv_spawn可能會返回即使遇到錯誤零issue,在這些情況下,您需要檢查process.spawn_error,它只存在於Windows上。