C-将管道穿过Exeve

C-将管道穿过Exeve,c,exec,pipe,execve,C,Exec,Pipe,Execve,我正在为学校做一个项目,我不确定我试图解决这个问题的方法是否可行。该项目包括制作一个程序,分叉出两个孩子,然后用其他程序替换他们的pid,并让这两个孩子通过管道通过读写进行对话 我的问题是如何使用execve并将管道传递给那个孩子。我现在得到的是: 父程序-分叉并让子调用execve: #include <unistd.h> #include <stdio.h> #include <errno.h> #include <stdlib.h> #inc

我正在为学校做一个项目,我不确定我试图解决这个问题的方法是否可行。该项目包括制作一个程序,分叉出两个孩子,然后用其他程序替换他们的pid,并让这两个孩子通过管道通过读写进行对话

我的问题是如何使用execve并将管道传递给那个孩子。我现在得到的是:

父程序-分叉并让子调用execve:

#include <unistd.h>
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <fcntl.h>

#define BUF_SIZE 16

/*  2 cmd line arguments
    1. file already in system (to be copied)
    2. file to be created (the copy)
create pipe (for communication) + 2 child processes
    first child replace pid with reader
    second child with writer
    wait for both children to terminate before exiting
*/

int main(int argc, char* argv[]){

//making the pipe
int pfd[2];
pipe(pfd);

int num_dead;

//forking
pid_t reader_child_pid;
pid_t writer_child_pid;
pid_t child_pid;

//args for each fork
char *args_1[] = {argv[1], (char *) 0};
char *args_2[] = {argv[2], (char *) 0};

switch(writer_child_pid = fork()) {
    case -1:
        perror("fork failed");
        return 1;
    case 0:
        close(pfd[1]);
        dup2(pfd[0], 0);
        execve("./writer", args_2, NULL);
        perror("execve failed");
        break;
    default:
        switch(reader_child_pid = fork()) {
            case -1:
                perror("2nd fork failed");
                return 1;
            case 0:
                close(pfd[0]);
                dup2(pfd[1], 1);
                execve("./reader", args_1, NULL);
                perror("execve failed");
                break;
            default:
                //close(pfd[0]);
                //close(pfd[1]);
                break;
        }
}

num_dead = 0;

for(;;) {
    if((child_pid=wait(NULL)) == -1){
        if(errno == ECHILD) {
            printf("NO MORE CHILDREN");
            exit(0);
        } else {
            perror("wait error");
            exit(1);
        }
    }
    ++num_dead;
    printf("wait() returned 1 child");
}
}
正在尝试使用dup2重定向到stdin和stdout。然后,在孩子们身上,我试着像这样读写stdout和stdin:

从stdin读取数据

#include <unistd.h>
#include <stdio.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>

#define BUF_SIZE 16
int main(int argc, char* argv[]){
printf("\n\nWRITER\n");

    /* ready to process info
    read the file, write it to pipe */
int wri_inFile = open(argv[0], O_WRONLY | O_CREAT | O_TRUNC | S_IRUSR | S_IWUSR);

char buf[BUF_SIZE];
int read_test;
for(;;) {
    read_test = read(0, buf, BUF_SIZE);
    if(read_test == 0) //eof
        break;
    write(wri_inFile, buf, BUF_SIZE);
}

close(wri_inFile);
exit(0);
}
我是按照你的建议使用dup的,但我不确定我是按照标准DIN和标准DOUT做的

-这是另一个孩子,仅供参考

#include <unistd.h>
#include <stdio.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>

#define BUF_SIZE 16

int main(int argc, char* argv[]){

printf("\n\nREADER\n");

/* ready to process info
    read the file, write it to pipe */
printf("FILE::%s", argv[0]);
int inFile = open(argv[0], O_RDONLY);

char buf[BUF_SIZE];
int read_test;
for(;;) {
    read_test = read(inFile, buf, BUF_SIZE);
    if(read_test == 0) //eof
        break;
    write(1, buf, BUF_SIZE);
}
close(argv[0][1]);
close(inFile);
printf("\nDONE WITH READER\n");
exit(0);
}
-如果有什么不同的话,那么另一个向管道中写入的孩子似乎成功地向管道中写入了内容,但是上面的孩子从不从管道中读取内容,并且上面的输出文件总是空的

**还是发生了同样的事情

我不是在找你帮我解决问题,我只是真的被卡住了,不知道我是否做错了什么。再次感谢您的帮助


我正在积极地搜索示例,但我找不到任何显示他们执行的子级代码的示例,我的问题似乎就在这些示例中。

我在下面标记了问题

switch(reader_child_pid = fork()) {
    // ...
    default:
        close(pfd[1]); // <--------------------
        close(pfd[0]);
        switch(writer_child_pid = fork()) {
            // ...
            default:
                break;
        }
}

我把问题标在下面

switch(reader_child_pid = fork()) {
    // ...
    default:
        close(pfd[1]); // <--------------------
        close(pfd[0]);
        switch(writer_child_pid = fork()) {
            // ...
            default:
                break;
        }
}

使用管道时,必须确保流程不会保持管道打开,除非流程实际使用管道。特别是,在这种情况下,父进程必须关闭管道的两端,因为否则读取器将永远不会得到EOF指示

在更仔细地阅读了另外两个程序之后,我看到reader程序读取给定的文件并将内容写入管道,writer程序使用从管道读取的数据写入给定的文件

此代码是关于将工作的最小更改:

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

/*  2 cmd line arguments
    1. file already in system (to be copied)
    2. file to be created (the copy)
create pipe (for communication) + 2 child processes
    first child replace pid with reader
    second child with writer
    wait for both children to terminate before exiting
*/

int main(int argc, char* argv[])
{
    //making the pipe
    int pfd[2];
    pipe(pfd);      // Error check omitted!
    int num_dead;

    //forking
    pid_t reader_child_pid;
    pid_t writer_child_pid;
    pid_t child_pid;

    if (argc != 3)
    {
        fprintf(stderr, "Usage: %s infile outfile\n", argv[0]);
        return 1;
    }

    //args for each fork
    char *args_1[] = { "reader", argv[1], (char *) 0 };
    char *args_2[] = { "writer", argv[2], (char *) 0 };

    switch (writer_child_pid = fork()) {
        case -1:
            perror("fork failed");
            return 1;

        case 0:
            // writer reads from standard input (pipe) and writes to named file
            dup2(pfd[0], 0);  // Error check omitted
            close(pfd[0]);
            close(pfd[1]);
            execve("./writer", args_2, NULL);
            perror("execve failed");
            return 1;

        default:
            switch (reader_child_pid = fork()) {
            case -1:
                perror("2nd fork failed");
                return 1;

            case 0:
                //reader reads from the named file and writes to the pipe
                dup2(pfd[1], 1);
                close(pfd[0]);
                close(pfd[1]);
                execve("./reader", args_1, NULL);
                perror("execve failed");
                return 1;

            default:
                // The parent closes both ends of the pipe
                close(pfd[0]);
                close(pfd[1]);
                break;
        }
    }

    num_dead = 0;

    for(;;) {
        if ((child_pid = wait(NULL)) == -1){
            if (errno == ECHILD) {
                printf("NO MORE CHILDREN\n");
                exit(0);
            } else {
                perror("wait error");
                exit(1);
            }
        }
        ++num_dead;
        printf("wait() returned 1 child (%d)\n", (int)child_pid);
    }
    return(0);
}

我还有一个函数来封装“ReportErrorandExit”,即使它只有两行。此外,如果您确实希望printf中的消息及时显示,请确保它们以换行符结尾。

使用管道时,必须确保流程没有保持管道打开,除非流程实际使用管道。特别是,在这种情况下,父进程必须关闭管道的两端,因为否则读取器将永远不会得到EOF指示

在更仔细地阅读了另外两个程序之后,我看到reader程序读取给定的文件并将内容写入管道,writer程序使用从管道读取的数据写入给定的文件

此代码是关于将工作的最小更改:

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

/*  2 cmd line arguments
    1. file already in system (to be copied)
    2. file to be created (the copy)
create pipe (for communication) + 2 child processes
    first child replace pid with reader
    second child with writer
    wait for both children to terminate before exiting
*/

int main(int argc, char* argv[])
{
    //making the pipe
    int pfd[2];
    pipe(pfd);      // Error check omitted!
    int num_dead;

    //forking
    pid_t reader_child_pid;
    pid_t writer_child_pid;
    pid_t child_pid;

    if (argc != 3)
    {
        fprintf(stderr, "Usage: %s infile outfile\n", argv[0]);
        return 1;
    }

    //args for each fork
    char *args_1[] = { "reader", argv[1], (char *) 0 };
    char *args_2[] = { "writer", argv[2], (char *) 0 };

    switch (writer_child_pid = fork()) {
        case -1:
            perror("fork failed");
            return 1;

        case 0:
            // writer reads from standard input (pipe) and writes to named file
            dup2(pfd[0], 0);  // Error check omitted
            close(pfd[0]);
            close(pfd[1]);
            execve("./writer", args_2, NULL);
            perror("execve failed");
            return 1;

        default:
            switch (reader_child_pid = fork()) {
            case -1:
                perror("2nd fork failed");
                return 1;

            case 0:
                //reader reads from the named file and writes to the pipe
                dup2(pfd[1], 1);
                close(pfd[0]);
                close(pfd[1]);
                execve("./reader", args_1, NULL);
                perror("execve failed");
                return 1;

            default:
                // The parent closes both ends of the pipe
                close(pfd[0]);
                close(pfd[1]);
                break;
        }
    }

    num_dead = 0;

    for(;;) {
        if ((child_pid = wait(NULL)) == -1){
            if (errno == ECHILD) {
                printf("NO MORE CHILDREN\n");
                exit(0);
            } else {
                perror("wait error");
                exit(1);
            }
        }
        ++num_dead;
        printf("wait() returned 1 child (%d)\n", (int)child_pid);
    }
    return(0);
}

我还有一个函数来封装“ReportErrorandExit”,即使它只有两行。此外,如果您确实希望printf中的消息及时显示,请确保它们以换行符结尾。

您实际上并不是在这里创建管道。。您需要使用管道系统调用或进行fifo。请看一般的习惯用法是创建管道,然后分叉,然后在每个进程中关闭管道的一端,关闭写入线程上的读取端,反之亦然。然后需要执行dup以强制标准输入/标准输出使用管道。最后,读写器应该是从stdin/stdout读写的;管道;那是我做烟斗的地方。另外,在execve调用之前,我正在关闭管道的一端,这是错误的吗?分配给我的问题的一个限制是使用读写函数来处理对管道的读写,并将管道视为只有16个字节的缓冲区大小。这就是我使用读写函数的原因。这是可能的,还是我理解错了?你的孩子应该读标准输入,写标准输出。执行fork的父级应该在exec之前使用dup,以便将读取器的stdin设置为管道的读取句柄,并将写入器的stdout设置为管道。孩子们不关心它是管道这一事实。如果一个孩子在其stdin上读取管道,另一个孩子在其stdout上写入管道,那么两个孩子最终都会关闭管道返回的两个文件描述符;您的dup2或dup调用创建了相关管道描述符的副本。我使用dup2从所有3个不同文件编辑了代码,以关闭管道并将其重定向到stdin和stdout。我不确定的是,我现在是否正确使用了孩子们的读写功能。它似乎仍然挂起并创建一个空文件。

感谢您迄今为止的帮助,如果我不理解一些应该非常简单的事情,我很抱歉。您实际上并不是在这里创建管道。。您需要使用管道系统调用或进行fifo。请看一般的习惯用法是创建管道,然后分叉,然后在每个进程中关闭管道的一端,关闭写入线程上的读取端,反之亦然。然后需要执行dup以强制标准输入/标准输出使用管道。最后,读写器应该是从stdin/stdout读写的;管道;那是我做烟斗的地方。另外,在execve调用之前,我正在关闭管道的一端,这是错误的吗?分配给我的问题的一个限制是使用读写函数来处理对管道的读写,并将管道视为只有16个字节的缓冲区大小。这就是我使用读写函数的原因。这是可能的,还是我理解错了?你的孩子应该读标准输入,写标准输出。执行fork的父级应该在exec之前使用dup,以便将读取器的stdin设置为管道的读取句柄,并将写入器的stdout设置为管道。孩子们不关心它是管道这一事实。如果一个孩子在其stdin上读取管道,另一个孩子在其stdout上写入管道,那么两个孩子最终都会关闭管道返回的两个文件描述符;您的dup2或dup调用创建了相关管道描述符的副本。我使用dup2从所有3个不同文件编辑了代码,以关闭管道并将其重定向到stdin和stdout。我不确定的是,我现在是否正确使用了孩子们的读写功能。它似乎仍然挂起并创建一个空文件。感谢到目前为止的帮助,如果我不理解一些应该非常简单的内容,我很抱歉。我的代码不再锁定文件,而是按照预期复制文件,但它也会从reader函数中的printf语句向文件复制几行额外的文本。但是,如果我删除那些不必要的printf语句,即文件::%s,argv[0]的语句,则程序会崩溃,根本无法工作。我想我知道为什么会发生这种情况,在我的书写器底部,当我关闭文件时,我相信它会从留在缓冲区中的打印语句中提取额外的字符。删除printf仍然会破坏程序。很抱歉,一切正常。我一定没有保存文件,或者没有在那里的某个地方编译新保存的文件。非常感谢您的帮助。我的代码不再锁定,而是按照预期复制文件,但是它也会从reader函数中的printf语句向文件复制几行额外的文本。但是,如果我删除那些不必要的printf语句,即文件::%s,argv[0]的语句,则程序会崩溃,根本无法工作。我想我知道为什么会发生这种情况,在我的书写器底部,当我关闭文件时,我相信它会从留在缓冲区中的打印语句中提取额外的字符。删除printf仍然会破坏程序。很抱歉,一切正常。我一定没有保存文件,或者没有在那里的某个地方编译新保存的文件。非常感谢你的帮助。非常感谢你的投入。我计划在我的代码按预期运行后,用您的建议清理我的代码。我真的很感激你花时间把它全部打印出来,告诉我我做错了什么;您应该将权限位放入第三个参数:int-wri_-infle=openargv[0],O_-WRONLY | O|u-CREAT | O|u-TRUNC,S|u-IRUSR | S|u-IWUSR;我确实注意到了,但谢谢你指出这一点。为了使我的代码更具可读性/更好地实现,我几乎已经完全实现了您的所有建议。它帮助我更容易地认识到实际发生的事情。再次感谢。非常感谢您的投入。我计划在我的代码按预期运行后,用您的建议清理我的代码。我真的很感激你花时间把它全部打印出来,告诉我我做错了什么;您应该将权限位放入第三个参数:int-wri_-infle=openargv[0],O_-WRONLY | O|u-CREAT | O|u-TRUNC,S|u-IRUSR | S|u-IWUSR;我确实注意到了,但谢谢你指出这一点。为了使我的代码更具可读性/更好地实现,我几乎已经完全实现了您的所有建议。它帮助我更容易地认识到实际发生的事情。再次感谢。