【问题标题】:Writing a term to bc via pipes in C通过 C 中的管道向 bc 写入一个术语
【发布时间】:2016-12-06 12:14:27
【问题描述】:

我在这个 C 练习中遇到了问题。 任务是创建两个进程。两者通过两个管道连接,这些管道终止于子节点的标准输入和标准输出。然后将子进程替换为 bc。 然后我应该写一个从父进程到子进程(bc)的术语(例如1 + 2)。

管道正在做他们应该做的事情,但是,bc 似乎不喜欢输入。当我写入管道时, bc 会响应以下多行:

(standard_in) 1: illegal character: ^@

这是我目前的解决方案:

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

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

    /*Create two pipes:
        One from parent to child (pipe_pc)
        and one from child to parent (pipe_cp).
    */
    int pipe_pc[2], pipe_cp[2];

    int cid;

    if (pipe(pipe_pc) == -1 || pipe(pipe_cp) == -1) {
        printf("Could not pipe\n");
        exit(EXIT_FAILURE);
    }

    // Create child process
    cid = fork();

    if (cid == -1) {
        printf("Could not fork.\n");
        exit(EXIT_FAILURE);
    }

    // Child process
    if (cid == 0) {

        // Redirect pipes
        close(STDOUT_FILENO);
        close(STDIN_FILENO);
        close(pipe_pc[1]); // Close writing end
        close(pipe_cp[0]); // Close reading end

        dup2(pipe_pc[0], STDIN_FILENO); // Take stdin from parent
        dup2(pipe_cp[1], STDOUT_FILENO); // Give stdout to parent

        int err;

        // Replace child with bc
        err = execl("/usr/bin/bc", "bc --quiet", (char*) NULL);

        printf("%s %d\n", "Could not start bc:", err);
        exit(err);
    }

    // Parent Process
    else {

        char input[128] = "";
        char buffer[128] = "";

        printf("%s\n", "Parent process running");

        // Copy argv to a single string
        for(int i=1; i < argc; i++) {
            strcat(input, argv[i]);
        }

        // Write the input to the child's stdin
        write(pipe_pc[1], input, sizeof(input);

        // Read the child's stdout
        read(pipe_cp[0], buffer, sizeof(buffer));

        printf("Result: %s\n", buffer);

        return 0;
    }

}

非常感谢您的提示和帮助,在此先感谢!

【问题讨论】:

    标签: c pipe bc


    【解决方案1】:

    问题是你没有在管道中正确写入,所以 bc 收到了错误的输入。

    我重写了else 分支。

    如果您不确定在管道中发送了什么,请将管道描述符暂时替换为 0 (i/o fd),然后直观地检查您所做的。

    #include <stdio.h>
    #include <string.h>
    #include <stdlib.h>
    #include <unistd.h>
    
    int main(int argc, char *argv[]) {
    
        /* Create two pipes: One from parent to child (pipe_pc) and one
           from child to parent (pipe_cp).
        */
        int pipe_pc[2], pipe_cp[2];
    
        int cid;
    
        if (pipe(pipe_pc) == -1 || pipe(pipe_cp) == -1) {
            printf("Could not pipe\n");
            exit(EXIT_FAILURE);
        }
    
        // Create child process
        cid = fork();
    
        if (cid == -1) {
            printf("Could not fork.\n");
            exit(EXIT_FAILURE);
        }
    
        // Child process
        if (cid == 0) {
    
            // Redirect pipes
            close(STDOUT_FILENO);
            close(STDIN_FILENO);
            close(pipe_pc[1]); // Close writing end
            close(pipe_cp[0]); // Close reading end
    
            dup2(pipe_pc[0], STDIN_FILENO); // Take stdin from parent
            dup2(pipe_cp[1], STDOUT_FILENO); // Give stdout to parent
    
            int err;
    
            // Replace child with bc
            err = execl("/usr/bin/bc", "bc --quiet", (char*) NULL);
    
            printf("%s %d\n", "Could not start bc:", err);
            exit(err);
        }
    
        // Parent Process
        else {
            char buffer[128] = "";
    
            // printf("%s\n", "Parent process running");
    
            for(int i=1; i < argc; i++)
                write(pipe_pc[1], argv[i], strlen(argv[i]));
    
            write(pipe_pc[1], "\n", 1);
    
            read(pipe_cp[0], buffer, sizeof(buffer));
    
            printf("Result: %s\n", buffer);
    
            return 0;
        }
    
    }
    

    【讨论】:

      【解决方案2】:

      您的代码有很多未定义的行为。


      write(pipe_pc[1], input, sizeof(input);
      

      你写所有的输入数组。但是你只需要写你用strcat()复制的东西。 使用 strlen。

      write(pipe_pc[1], input, strlen(input));
      

      strcat(input, argv[i]);
      

      您应该在此处验证您不超过 128 个八位字节。

      if (strlen(input) + strlen(argv[i]) + 1 > 128) {
        break;
      }
      strcat(input, argv[i]);
      

      read(pipe_cp[0], buffer, sizeof(buffer));
      

      这里你没有验证缓冲区是一个有效的 c 字符串。

      ssize_t ret = read(pipe_cp[0], buffer, sizeof(buffer) - 1);
      if (ret < 0)
        return 1;
      buffer[ret] = '\0';
      

      您忘记在父级中关闭管道

      close(pipe_pc[0]);
      close(pipe_cp[1]);
      

      在你读/写之后

      close(pipe_pc[1]);
      close(pipe_cp[0]);
      

      您在dup2() 之后忘记关闭子管道

      close(pipe_pc[1]);
      close(pipe_cp[0]);
      

      你不需要在 dup2 之前关闭你的旧 fd,他会为你做。而且你不检查dup2()的错误

      【讨论】:

        猜你喜欢
        • 2018-05-23
        • 2013-01-29
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-03-28
        • 1970-01-01
        • 2020-08-01
        相关资源
        最近更新 更多