C 捕获子进程';带libuv的s stdout

C 捕获子进程';带libuv的s stdout,c,spawn,libuv,C,Spawn,Libuv,我在用libuv。我已经读过了,但仍然无法解决如何捕获子进程的stdout,以便它在父进程中可用(但不能代替父进程的stdin) 我的代码当前为: #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;

我在用libuv。我已经读过了,但仍然无法解决如何捕获子进程的stdout,以便它在父进程中可用(但不能代替父进程的stdin)

我的代码当前为:

#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);
}
#包括
#包括
#包括“../../libuv/include/uv.h”
uv_环_t*环;
uv_工艺_t子_要求;
紫外线处理选项;
紫外线管;
子项退出时无效(uv处理请求、int退出状态、int term信号){
fprintf(标准,“进程退出,状态为%d,信号为%d\n”,退出状态,术语为信号);
uv_关闭((uv_句柄*)请求,NULL);
}
紫外缓冲区(紫外手柄,大小透镜){
printf(“称为alloc_缓冲区的\n”);
紫外线照射;
buf.base=malloc(len);
buf.len=len;
返回buf;
}
无效读取apipe(uv\u流\u t*流、ssize\u t nread、uv\u buf\u t buf){
printf(“从子进程读取%li字节”,nread);
}
int main(int argc,char*argv[]){
printf(“繁殖测试”\n);
loop=uv_default_loop();
char*args[3];
args[0]=“虚拟”;
args[1]=NULL;
args[2]=NULL;
uv_管道_init(回路和apipe,0);
uv管道打开(&apipe,0);
options.stdio_count=3;
uv_stdio_container_u t child_stdio[3];
child_stdio[0]。标志=UV_忽略;
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\u stdio;
options.exit_cb=在子项上_exit;
options.file=args[0];
options.args=args;
uv_读取_开始((uv_流_t*)和apipe、分配缓冲区、读取apipe);
if(uv_繁殖(循环和子_请求,选项)){
fprintf(stderr,“%s\n”,uv_strerror(uv_last_error(loop));
返回1;
}
返回uv_运行(循环,uv_运行默认值);
}
D.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;
}
#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;
}
#包括
#包括
int main(){
printf(“子启动\n”);
睡眠(1);
printf(“子运行\n”);
睡眠(2);
printf(“子结尾\n”);
返回0;
}

我有一种烦人的感觉,我还不太了解libuv管道的意义。

我找到了解决方案:

  • 我使用了错误的标志,它们应该是
    UV\u CREATE\u PIPE | UV\u READABLE\u PIPE
    而不是
    UV\u INHERIT\u STREAM
  • 我需要在
    uv\u spawn
    之后调用
    uv\u read\u start
    。我假设数据不会丢失,因为还没有调用uv_run
  • 上述两个修复程序显示了从
    dummy
    到一次到达的所有输出,而不是三次到达(就像在命令行上那样)。
    dummy.c中的
    fflush
    修复了此问题
  • 繁殖试验:

    #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);
    }
    
    #包括
    #包括
    #包括“../../libuv/include/uv.h”
    uv_环_t*环;
    uv_工艺_t子_要求;
    紫外线处理选项;
    紫外线管;
    子项退出时无效(uv处理请求、int退出状态、int term信号){
    fprintf(标准,“进程退出,状态为%d,信号为%d\n”,退出状态,术语为信号);
    uv_关闭((uv_句柄*)请求,NULL);
    }
    紫外缓冲区(紫外手柄,大小透镜){
    printf(“调用alloc_缓冲区,请求%lu字节缓冲区\n”);
    紫外线照射;
    buf.base=malloc(len);
    buf.len=len;
    返回buf;
    }
    无效读取apipe(uv\u流\u t*流、ssize\u t nread、uv\u buf\u t buf){
    printf(“在%lu字节缓冲区中读取%li字节,\n”,nread,buf.len);
    如果(nread+1>buf.len)返回;
    buf.base[nread]='\0';//将其转换为cstring
    printf(“读取:|%s |”,基本单位);
    }
    int main(int argc,char*argv[]){
    printf(“繁殖测试”\n);
    loop=uv_default_loop();
    char*args[3];
    args[0]=“虚拟”;
    args[1]=NULL;
    args[2]=NULL;
    uv_管道_init(回路和apipe,0);
    uv管道打开(&apipe,0);
    options.stdio_count=3;
    uv_stdio_container_u t child_stdio[3];
    child_stdio[0]。标志=UV_忽略;
    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\u stdio;
    options.exit_cb=在子项上_exit;
    options.file=args[0];
    options.args=args;
    if(uv_繁殖(循环和子_请求,选项)){
    fprintf(stderr,“%s\n”,uv_strerror(uv_last_error(loop));
    返回1;
    }
    uv_读取_开始((uv_流_t*)和apipe、分配缓冲区、读取apipe);
    返回uv_运行(循环,uv_运行默认值);
    }
    
    D.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;
    }
    
    #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;
    }
    
    #包括
    #包括
    int main(){
    printf(“子启动\n”);
    fflush(stdout);
    睡眠(1);
    printf(“子运行\n”);
    fflush(stdout);
    睡眠(2);
    printf(“子结尾\n”);
    fflush(stdout);
    返回0;
    }
    
    查看他们如何在libuv单元测试中执行此操作:

    • 不要呼叫
      uv\u管道\u打开
    • 儿童标准的标志:
      UV_创建_管道| UV_可读_管道
    • 儿童标准输出和标准输出的标志:
      UV_创建_管道| UV_可写_管道
    Windows上还有一个错误,其中
    uv\u spawn
    即使遇到错误也可能返回零,在这种情况下,您需要检查仅存在于Windows上的
    process.spawn\u error