简体   繁体   English

如何在 c 中使用 pipe 和 dup2

[英]How to use pipe and dup2 in c

I have to simulate this command using pipes in c: echo "<exp>" |我必须使用 c 中的管道来模拟此命令: echo "<exp>" | bc -lq.公元前-lq。 Process A must read a string and send it to process B;进程 A 必须读取一个字符串并将其发送给进程 B; Process B executes the "bc -lq" command and returns the result to A.进程 B 执行“bc -lq”命令并将结果返回给 A。

The code is this, but I can't understand why it doesn't work;代码是这样的,但我不明白为什么它不起作用; in particular, the "bc" command appears to be unable to read the expression from stdin.特别是,“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);
    }
}

You are writing all 1024 bytes of the mostly uninitialized stringa to bc , which is then choking on illegal characters.您正在将大部分未初始化的stringa的所有 1024 个字节写入bc ,然后它会因非法字符而窒息。 bc expects newline terminated, "plain text" expressions. bc期望换行符终止的“纯文本”表达式。

#define N 1024
char stringa[N];      // stringa := "\236\0\0\241\177>\0\0\3704\241..."

scanf("%s", stringa); // stringa := "1+2\0\177>\0\0\3704\241..."
                      //                ^^^^^^^^^^^^^^^^^^^^
....
Write(pipeFd[1], stringa, N);  // ohimè!

You'll want something like this, instead:你会想要这样的东西,而不是:

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

I think my code is similar to yours, one main change was the arguments to the exec call.我认为我的代码与您的代码相似,一个主要变化是 arguments 到 exec 调用。 Another change was that I only have 2 dup2 calls in the child process, one for changing stdin and the other for stdout.另一个变化是我在子进程中只有 2 个 dup2 调用,一个用于更改标准输入,另一个用于标准输出。 You only need to change these.你只需要改变这些。

#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')) = '\0'; // Add null terminator on your own

        close(fd_return[READ_END]);

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

    }

    free(input);

    return 0;
}

EDIT: I edited the code and debugged it.编辑:我编辑了代码并对其进行了调试。 I also changed the user input schematic so now you no longer allocated static storage for the user input, rather it is allocated dynamically and then this storage is freed at the end with free();我还更改了用户输入原理图,因此现在您不再为用户输入分配 static 存储,而是动态分配,然后在最后使用 free() 释放该存储;

Note, I did leave the static storage for reading the input back in, you can change this in the future if you want.请注意,我确实保留了 static 存储以重新读取输入,您可以在将来根据需要更改此设置。

illegal character: ^@ comes from the fact that write() was writing too much, notice that now we only write strlen(buff) amount.非法字符:^@ 来自于 write() 写的太多,注意现在我们只写 strlen(buff) 数量。

Note: The input to bc will not work unless the string ends like "...\n\0" luckily getline() does this by default.注意:除非字符串以 "...\n\0" 结尾,否则 bc 的输入将不起作用,幸运的是 getline() 默认情况下会这样做。

Also, I left all the pipe closing the same, that was not causing the issue.此外,我让所有 pipe 关闭相同,这不会导致问题。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM