通过管道(C)写入外部程序

问题描述 投票:1回答:1

我想使用外部程序来处理内存中的数据。像外部压缩器,编码器一样,任何可以处理我的数据并获得结果的东西。我读了很多关于管道的内容,但仍然无法正常工作。因此,我得到了一个简单的程序,该程序试图通过这样的管道写入外部程序,然后将其打印到stdout:

                                                     stdout
             (w) pipeA (r)          $prog            +---+
             +-----------+       /~~~~~~~~~~~\       |{1}|
             |[1]     [0]| ----> |{0}     {1}| ----> |   |
        +~~> +-----------+       \~~~~~~~~~~~/       |   |
        |                                            +---+
        |
       +-+
 write() |
       +-+

而且我仍然一无所获。我的代码是这样的:

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

#define PIP_RD_0 0 /* read end of pipe file descriptor */
#define PIP_WR_1 1 /* write end of pipe file descriptor */

int main(void)
{
    int pipA[2];
    int pid;
    char buf_IN[32] = "Hello pipe!\n";
    char buf_OUT[32];
    ssize_t n_written, n_read;

    if ((pipe(pipA) == -1))    {
        perror("pipe failed");
        exit(1);
    }
    if ((pid = fork()) < 0)    {
        perror("fork failed");
        exit(2);
    }
    /*****************************/

    if (pid == 0)
        { /* in child */
        dup2(0, pipA[0]);   // pipA[read(0)-end]->$prog[write{0}-end]
        close(pipA[1]);   // $prog won't write to this pipe(A)
        // external ``$prog''ram
        execlp("wc", "wc", (char *) 0);   // out should be: '      1       2      12'
        //execlp("base64", "base64", (char *) 0);   // out should be: 'SGVsbG8gcGlwZSEK'

        ;///if we're here something went wrong
        perror("execlp() @child failed");
        exit(3);
        }

    else
        { /* in parent */
        //dup2(pipA[1], 0);  // STDIN -> pipA // that supposed to connect STDIN->pipA; just in case I needed it
        close(pipA[0]);  // we won't read it, let $prog write to stdout
        //perror("execlp() @parent failed");
        //exit(4);
        n_written = write(pipA[1], buf_IN, strlen(buf_IN));
        close(pipA[1]);  // I guess this will close the pipe and send child EOF

        // base64: read error: Input/output error
        // wc: 'standard input': Input/output error
        //      0       0       0
        }

return 0;
}

评论显示我在做什么。我必须承认我没有在管道中获得这些dup(),这就是我在这里引起问题的原因,但不知道。您可以解决这个看似简单的问题吗?任何帮助表示赞赏。

c pipe ipc
1个回答
0
投票

诊断

您具有从头到尾的dup2()的参数。您需要:

sup2(pipA[0], 0);

关闭文件描述符

如注释中所述,您没有在子级中关闭足够的文件描述符:


拇指法则:如果您dup2()管道的一端到标准输入或标准输出,同时关闭两个由返回的原始文件描述符dup2()尽快地。特别是,在使用任何pipe()功能系列。

如果您将描述符与pipe()要么exec*()exec*()


如果父进程不会通过以下方式与其任何子进程通信,管道,必须确保尽早关闭管道的两端足够(例如在等待之前),以便其子代可以接收EOF指示在读取(或获取SIGPIPE信号或在写),而不是无限期地阻止。即使父级在不使用dup()的情况下使用管道,也应通常至少会关闭管道的一端,这种情况极少发生一个在单个管道的两端进行读写的程序。

请注意,dup()选项fcntl(),并且fcntl()F_DUPFDdup2()选项也可以进入讨论。

如果您使用O_CLOEXEC及其广泛的支持功能系列(总共21个功能),您将需要查看如何在生成的过程中关闭文件描述符(open(),等)。

请注意,使用open()比使用FD_CLOEXEC更安全由于多种原因。一种是如果您要强制文件描述符大于通常,F_DUPFD_CLOEXEC是唯一可行的方法。另一个是如果fcntl()posix_spawn()相同(例如,两个posix_spawn()),则posix_spawn_file_actions_addclose()正确处理它(在复制posix_spawn_file_actions_addclose()之前不会关闭dup2(a, b))而单独的close(b); dup(a, b)dup2()严重失败。这是不可能的情况,但也不是不可能的情况。


处方

您的代码中也有一些未使用的定义和未使用的变量。留下所有评论,并进行适当的修复,最后我得到:

a

运行时产生:

b

看起来不错。

© www.soinside.com 2019 - 2024. All rights reserved.