【问题标题】:libuv : parent-child process communication through pipeslibuv:通过管道进行父子进程通信
【发布时间】:2022-12-10 19:41:23
【问题描述】:

我正在尝试编写一个程序,让父进程通过管道从两个子进程接收一些数据。当我有一个子进程时,程序运行良好,父进程从子进程接收数据。但是,当我有两个子进程时,父进程无法从子进程接收数据。 下面是我的代码: 子进程:test.cpp

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

using namespace std;

int main(int argc, char **argv) {
    if (argc <= 1) {
        printf("params error !\n");
        return -1;
    }
    string index = argv[1];
    if (index.empty()) {
        printf("params error !\n");
        return -1;
    }
    int num = 0;
    string s1 = "fourth stdio! " + index + "\n";
    while (num < 100) {
        num++;
        ssize_t r;

        do
            r = write(3, s1.c_str(), sizeof(s1) - 1);
        while (r == -1);

        fsync(3);
        sleep(1);
    }
    return 0;
}

父进程:main.cpp

#include <stdio.h>
#include <string.h>
#include <inttypes.h>
#include <stdlib.h>
#include <string>
#include <uv.h>

using namespace std;
uv_loop_t *loop;


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

void alloc_buffer(uv_handle_t *handle, size_t suggested_size, uv_buf_t *buf) {
    *buf = uv_buf_init((char *) malloc(suggested_size), suggested_size);
}

void on_read(uv_stream_t *client, ssize_t nread, const uv_buf_t *buf) {
    if (nread < 0) {
        if (nread != UV_EOF)
            fprintf(stderr, "Read error %s\n", uv_err_name(nread));
        uv_close((uv_handle_t *) client, NULL);
        free(buf->base);
        return;
    }

    char *data = (char *) malloc(sizeof(char) * (nread + 1));
    data[nread] = '\0';
    strncpy(data, buf->base, nread);

    fprintf(stdout, "%s", data);
    free(data);
    free(buf->base);
}


int main() {
    loop = uv_default_loop();

    for (int i = 0; i < 2; i++) {// The variable i controls the number of child processes
        uv_process_t child_req;
        string path = "/home/kanong/code/test_project/test";

        char *args[3];
        args[0] = (char *) path.c_str();
        args[1] = (char *) to_string(i).c_str();
        args[2] = NULL;

        /* ... */
        uv_pipe_t pipe;
        uv_pipe_init(loop, &pipe, 0);
        uv_stdio_container_t child_stdio[4];
        uv_process_options_t options = {0};
        options.stdio_count = 4;
        options.stdio = child_stdio;


        child_stdio[0].flags = UV_IGNORE;
        child_stdio[1].flags = UV_INHERIT_FD;
        child_stdio[1].data.fd = 1;
        child_stdio[2].flags = UV_INHERIT_FD;
        child_stdio[2].data.fd = 2;
        child_stdio[3].flags = (uv_stdio_flags) (UV_CREATE_PIPE | UV_WRITABLE_PIPE);
        child_stdio[3].data.stream = (uv_stream_t *) &pipe;

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

        int r;
        if ((r = uv_spawn(loop, &child_req, &options))) {
            fprintf(stderr, "%s\n", uv_strerror(r));
            return 1;
        }
        if ((r = uv_read_start((uv_stream_t *) &pipe, alloc_buffer, on_read))) {
            fprintf(stderr, "%s\n", uv_strerror(r));
            return 1;
        }

    }

    return uv_run(loop, UV_RUN_DEFAULT);
}

如何解决这个问题呢? 请帮忙。很感谢。

【问题讨论】:

  • 为什么你的 C++ 程序几乎完全没有 C++?几乎所有都是普通的 C。我认为你需要退后几步,先学习基本的 C++。
  • to_string(i).c_str() 在该行结束后变成了悬空指针,但我想你的问题的根源是 pipe 对于你的循环的两次调用结果是在同一个地址。您应该阅读悬挂指针以及如何避免它们。

标签: c++ pipe ipc libuv


【解决方案1】:

使用一个小的 struct 将每个孩子的状态存储在一个单独的位置:

struct child_process {
        uv_process_t child_req;
        uv_pipe_t pipe;
        std::string num;
} children[CHILDREN_COUNT];

然后你的主循环简单地引用children的元素:

for (int i = 0; i < CHILDREN_COUNT; i++) {
        child_process &proc = children[i];
        proc.num = std::to_string(i);
        std::string path = "/home/kanong/code/test_project/test";

        char *args[3];
        args[0] = (char *) path.c_str();
        args[1] = (char *) proc.num.c_str();
        args[2] = NULL;

        /* ... */
        uv_pipe_init(loop, &proc.pipe, 0);
        uv_stdio_container_t child_stdio[4];
        uv_process_options_t options = {0};
        options.stdio_count = 4;
        options.stdio = child_stdio;


        child_stdio[0].flags = UV_IGNORE;
        child_stdio[1].flags = UV_INHERIT_FD;
        child_stdio[1].data.fd = 1;
        child_stdio[2].flags = UV_INHERIT_FD;
        child_stdio[2].data.fd = 2;
        child_stdio[3].flags = (uv_stdio_flags) (UV_CREATE_PIPE | UV_WRITABLE_PIPE);
        child_stdio[3].data.stream = (uv_stream_t *) &proc.pipe;

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

        int r;
        if ((r = uv_spawn(loop, &proc.child_req, &options))) {
                fprintf(stderr, "%s
", uv_strerror(r));
                return 1;
        }
        if ((r = uv_read_start((uv_stream_t *) &proc.pipe, alloc_buffer, on_read))) {
                fprintf(stderr, "%s
", uv_strerror(r));
                return 1;
        }
}

【讨论】:

    【解决方案2】:

    在窗户上

    1. 使管道标志可写
    2. 子进程必须每次都用管道调用 fflush()

    【讨论】:

      猜你喜欢
      • 2011-12-22
      • 1970-01-01
      • 2021-12-16
      • 2017-09-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多