【问题标题】:How do you create Unix pipes dynamically?如何动态创建 Unix 管道?
【发布时间】:2014-04-16 02:23:16
【问题描述】:

我有一个程序使用fork() 创建子进程,我想让子进程使用 Unix 管道与父进程通信。

问题是似乎没有创建多个管道,或者我的数组可能有问题。当我在父程序中使用prinf() 时,它从每个管道读取相同的数据,即使每个子程序发送不同的数据。

这是我的代码:

// Variables
int pipes_count = 0;
int *pipes[MAXCLIENTS];
int new_pipefd[2];
int pipe_bytes;
char pipe_buffer[MAXDATASIZE];

while(1) {
    // Pipe creation 
    pipe(new_pipefd);
    pipes[pipes_count] = new_pipefd;
    pipes_count++;

    if (fork()) {
        // unrelated code for parent here
        close(new_pipefd[1]); // close the parent's write-end of the pipe
        break;
    } else {
        // unrelated code for child here
        close(new_pipefd[0]); // close the child's read-end of the pipe
        break;
    }

    if (some condition) { break; } // The parent will stop creating pipes
}

while(condition that guarantees this is the child) {
    write(new_pipefd[1], buffer, strlen(recv_buffer));
    close(new_pipefd[1]);
    return 0; // the child process ends
}

// This is a loop where the parent reads what the children sent
for (int i = 0; i < pipes_count; i++) {
    pipe_bytes = read(pipes[i][0], pipe_buffer, sizeof pipe_buffer);
    if (pipe_bytes == 0) {
        close(pipes[i][0]); 
    } else {
        printf("Testing: %s\n", pipe_buffer);
    }
}

【问题讨论】:

  • 你不能像C中的pipes[pipes_count] = new_pipefd;那样做数组赋值。你需要检查fork()的返回值来知道代码是父代码还是子代码。通过显示的代码,我们无法判断您到底在做什么;提到了一个循环,但你要做什么真的很重要。子进程在完成子进程的代码后,显然最终会执行父进程的代码。请发布更多您的真实代码 - 有很多事情可能会出错,很难猜测您遇到了什么问题。
  • 那我怎样才能得到一个管道数组(文件描述符)呢?为了简单起见,我从这篇文章中删除了检查 fork() 的返回值的代码,我应该让 cmets 更清晰。在我的实际源代码中,让代码在父级与子级中运行正常。编辑:刚刚看到你的编辑。我会回去尝试让一切更清楚。
  • 我收回;你的pipesint * 的数组,而不是int;我的错。但是,您的代码似乎将指针 new_pipefd 复制到数组中的每个位置,这不会有太大帮助。您需要能够存储不同的值。由于您没有显示所有代码,我们无法判断您是否正确但没有显示它。然而,从表面上看,一切都是从最后一个孩子那里读来的。您需要父进程关闭管道的写入端。事实上,一般来说,使用管道,很多问题都是由于没有关闭足够多的文件描述符造成的。

标签: c unix pipe


【解决方案1】:

正如我在我的 cmets 中指出的,问题出在分配 pipes[pipes_count] = new_pipefd; 中:

int pipes_count = 0;
int *pipes[MAXCLIENTS];
int new_pipefd[2];
int pipe_bytes;
char pipe_buffer[MAXDATASIZE];

while(1) {
    // Pipe creation 
    pipe(new_pipefd);
    pipes[pipes_count] = new_pipefd;
    pipes_count++;

问题在于变量new_pipefd 是一个数组,因此您将同一数组的地址复制到pipes 的每个元素中,这意味着父级只能访问最后一个管道已创建。

我认为你应该使用更像这样的代码:

int pipes_count = 0;
int pipes[MAXCLIENTS];  // Changed type!
int new_pipefd[2];
char pipe_buffer[MAXDATASIZE];

while (1)
{
    // Pipe creation 
    pipe(new_pipefd);
    pipes[pipes_count++] = new_pipefd[0];  // Just the read end of the pipe

    if (fork())
    {
        // unrelated code for parent here
        close(new_pipefd[1]); // close the parent's write-end of the pipe
        // break;             // This break is not wanted
    }
    else
    {
        // unrelated code for child here
        close(new_pipefd[0]); // close the child's read-end of the pipe
        break;
    }

    if (some condition)
        break;        // The parent will stop creating pipes
}

while (condition that guarantees this is the child)
{
    write(new_pipefd[1], buffer, strlen(recv_buffer));
    close(new_pipefd[1]);
    return 0; // the child process ends
}

// This is a loop where the parent reads what the children sent
for (int i = 0; i < pipes_count; i++) {
    int pipe_bytes = read(pipes[i], pipe_buffer, sizeof(pipe_buffer));
    if (pipe_bytes != 0)
        printf("Testing: %.*s\n", pipe_bytes, pipe_buffer); // Safe!
    close(pipes[i]); 
}

如果它是我的代码,我将有一个函数(我通常称之为be_childish())在循环中的“如果它是子”代码块中调用。该函数永远不会返回,并且会传递它需要的任何资源(当然是new_pipefd,也许还有其他信息)。我经常有一个功能be_parental()来做家长活动。我发现这会清理大部分代码,强制将活动完全分离。

【讨论】:

    猜你喜欢
    • 2023-03-21
    • 1970-01-01
    • 1970-01-01
    • 2011-07-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-10-27
    相关资源
    最近更新 更多