如何在 C 中使用管道和 dup2

How to use pipe and dup2 in c

我必须在 c 中使用管道模拟此命令: echo "" |公元前-lq。 进程A必须读取一个字符串并发送给进程B; 进程B执行“bc -lq”命令,returns结果给A.

代码是这样的,但是我不明白为什么它不起作用;特别是,“bc”命令似乎无法从标准输入中读取表达式。

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<sys/wait.h>

#define N 1024

#define LEGGI(stringa)  if(scanf("%s", stringa) == 0)                 \
                        {                                             \
                            perror("Impossibile leggere la stringa"); \
                            exit(EXIT_FAILURE);                       \
                        }                                             \

void closePipe(int pipeFd);
void Dup2(int pipeTempFd, int fd);
void Write(int pipeTempFd, char stringa[], int n);
void Read(int pipeTempFd, char stringa[], int n);

int main()
{

    char stringa[N];
    LEGGI(stringa);

    int pipeFd[2];
    int pRicezioneFd[2];

    if(pipe(pipeFd) == -1 || pipe(pRicezioneFd) == -1)
    {
        perror("impossibile eseguire la pipe");
        exit(EXIT_FAILURE);
    }

    if(strncmp(stringa, "exit", N) != 0)
    {
        pid_t processPid;
        if((processPid = fork()) == 1)
        {
            perror("impossibile eseguire la fork");
            exit(EXIT_FAILURE);
        }

        if(processPid != 0)
        {
            closePipe(pipeFd[0]);
            closePipe(pRicezioneFd[1]);

            printf("operazione: %s\n", stringa);

            Write(pipeFd[1], stringa, N);
            closePipe(pipeFd[1]);

            read(pRicezioneFd[0], stringa, N);

            closePipe(pRicezioneFd[0]);

            if(wait(NULL) == -1)
            {
                perror("Impossibile eseguire la wait");
                exit(EXIT_FAILURE);
            }

            printf("%s\n", stringa);
        }
        else
        {
            closePipe(pipeFd[1]);
            closePipe(pRicezioneFd[0]);

            Dup2(pipeFd[0], 0);
            Dup2(pRicezioneFd[1], 1);
            Dup2(pRicezioneFd[1], 2);


            // closePipe(pipeFd[0]);
            // closePipe(pRicezioneFd[1]);

            if(execl("/usr/bin/bc", "bc", "-lq", NULL) == -1)
            {
                perror("programma non reperibile");
                exit(EXIT_FAILURE);
            }
        }
    }

    return 0;
}
void closePipe(int pipeFd)
{
    if(close(pipeFd) == -1)
    {
        perror("impossibile chiudere il fd della pipe");
        exit(EXIT_FAILURE);
    }
}

void Dup2(int pipeTempFd, int fd)
{
    if(dup2(pipeTempFd, fd) == -1)
    {
        perror("Impossibile eseguire la dup2");
         exit(EXIT_FAILURE);
    }
}

void Write(int pipeTempFd, char stringa[], int n)
{
    if(write(pipeTempFd, stringa, n) == -1)
    {
        perror("impossibile scrivere sulla pipa");
        exit(EXIT_FAILURE);
    }
}

void Read(int pipeTempFd, char stringa[], int n)
{
    if(read(pipeTempFd, stringa, n) == -1)
    {
        perror("impossibile leggere dalla pipe pipa");
        exit(EXIT_FAILURE);
    }
}

我认为我的代码与您的相似,一个主要变化是 exec 调用的参数。另一个变化是我在子进程中只有 2 个 dup2 调用,一个用于更改标准输入,另一个用于更改标准输出。你只需要改变这些。

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<sys/wait.h>

#define N 1024
#define READ_END 0
#define WRITE_END 1

int main()
{
    char *input = NULL;
    size_t len = 0;
    ssize_t amt_read = 0;

    puts("Please enter a string: ");
    amt_read = getline(&input, &len, stdin);

    if(amt_read < 0)
        exit(EXIT_FAILURE);

    pid_t pid;

    int fd[2];
    int fd_return[2];

    // Create the pipes
    pipe(fd);
    pipe(fd_return);

    pid = fork();

    if(pid==0)
    {  // If child process
        dup2(fd[READ_END], STDIN_FILENO);
        dup2(fd_return[WRITE_END], STDOUT_FILENO);

        close(fd[WRITE_END]);
        close(fd[READ_END]);

        close(fd_return[WRITE_END]);
        close(fd_return[READ_END]);

        execl("/usr/bin/bc", "/usr/bin/bc", "-lq", (char *)NULL);

        fprintf(stderr, "Failed to execute\n");
        exit(EXIT_FAILURE);
    }
    else
    { // If parent process
        int status;
        close(fd[READ_END]);
        close(fd_return[WRITE_END]);

        // Write to the pipe
        write(fd[WRITE_END], input, strlen(input));

        close(fd[WRITE_END]);

        // Wait for the child to finish
        waitpid(pid, &status, 0);

        char buff[N];
        buff[N-1] = 0;

        read(fd_return[READ_END], buff, N-1);
        *(index(buff, '\n')) = '[=10=]'; // Add null terminator on your own

        close(fd_return[READ_END]);

        printf("The Result is: %s\n", buff);

    }

    free(input);

    return 0;
}

编辑: 我编辑了代码并调试了它。我还更改了用户输入原理图,所以现在您不再为用户输入分配静态存储空间,而是动态分配,然后在最后使用 free();

释放该存储空间

请注意,我确实留下了用于读取输入的静态存储,如果需要,您可以在以后更改它。

非法字符:^@是因为write()写的太多了,注意现在只写了strlen(buff)的数量

注意:除非字符串以“...\n[=23=]”结尾,否则 bc 的输入将不起作用,幸运的是 getline() 默认情况下会这样做。

另外,我让所有的管道都关闭了,这不是导致问题的原因。

您正在将大部分未初始化的 stringa 的所有 1024 个字节写入 bc,然后它会因非法字符而窒息。 bc 期望换行符终止,“纯文本”表达式。

#define N 1024
char stringa[N];      // stringa := "6[=10=][=10=]17>[=10=][=10=]041..."

scanf("%s", stringa); // stringa := "1+2[=10=]7>[=10=][=10=]041..."
                      //                ^^^^^^^^^^^^^^^^^^^^
....
Write(pipeFd[1], stringa, N);  // ohimè!

你会想要这样的东西,而不是:

Write(pipeFd[1], stringa, strlen(stringa));
Write(pipeFd[1], "\n", 1);