Parent从文件中读取操作,子项将其与bc

时间:2017-06-12 17:32:25

标签: c pipe fork dup2

我试图创建一个程序,其中父项从文件中读取一些操作,使用管道将它们传递给子项,并且子项使用bc进行所有操作。稍后,孩子必须将其传递回父母,并且必须将其写在文件上。

然而,当我执行它时,我没有得到任何结果,也不知道问题出在哪里。孩子似乎正确地接受了手术,但是有了&EXTS' EXT'字符。

当父母没有从文件中读取时,我的代码工作正常,问题是当我尝试从文件中读取时。

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

#define EOL '\n'

int main(int argc, char *argv[]){
    int tube1[2];
    int tube2[2];
    int fID;
    pipe(tube1);
    pipe(tube2);

    if(argc != 2){
        perror("./yourProgram.c [origin]");
        exit(EXIT_FAILURE);
    }

    if (fork() == 0){
        //Child Process

        close(tube1[1]); // writing end of the pipe
        dup2(tube1[0], 0);  // stdin ----> pipe reading end

        close(tube2[0]); // reading end of the pipe
        dup2(tube2[1], 1);  // stdout ---> pipe writing end

        //Execute and write the output in the tube2
        execlp("bc", "bc", "-q", NULL);
    }else {
        //Parent Process

        close(tube1[0]); // reading end of the pipe
        //dup2(tube1[1], 1); // stdout ---> pipe writing end

        close(tube2[1]); // reading end of the pipe
        //dup2(tube1[1], 1); // stdout ---> pipe writing end

     //Files
        //Destiny
        char *destiny = "final.txt";
        int destinyFile = open(destiny, O_WRONLY | O_CREAT | O_TRUNC, 0644);

        //Origin
        char *origin = argv[1];
        int originFile = open(origin, O_RDONLY);

        //Variables
        char block;
        char result;
        char buffer[4096];
        int i = 0;
        int numbytes;

        while(numbytes = read(originFile, &block, sizeof(block)) > 0){
            if(block == EOL){

                //Write on the tube, so the child can read it
                if(write(tube1[1], buffer, strlen(buffer)) == -1){
                    perror("error en write en pipe");
                    exit(EXIT_FAILURE);
                }

                //Read the child's answer
                while(numbytes = read(tube2[0], &result, 1) > 0){
                    if(result != EOL){
                        //Concatenate strings as: 'X + Y = Result \n'
                        char str[80];
                        strcat(str, buffer);
                        strcat(str, " = ");
                        strcat(str, &result);
                        strcat(str, "\n");

                        //Write the result in the Final File
                        if(write(destinyFile, str, strlen(str)) == -1){
                            perror("error en write en stdout");
                            exit(EXIT_FAILURE);
                        }
                    }else
                        continue;        
                }

                //Reset Buffer
                buffer[0] = '\0';
                i = 0;
             }else{
                buffer[i] = block;
                i = i + 1;
            }
        }
    }
}

我读到的文件是:

2+3
4*5
8/2
quit

1 个答案:

答案 0 :(得分:1)

此代码修复了注释中提到的关键问题(但不是一次读取一个字节的性能问题)。如果计算产生的结果足够大,bc将其输出分成多行(例如,计算因子100)。代码不会尝试处理这个问题。此外,某些操作不会产生任何输出。例如,c=2345不产生任何输出。该程序也没有处理这个问题。

您没有在孩子中关闭足够的文件描述符。 经验法则:如果你 dup2() 管道的一端到标准输入或标准输出,关闭两端 管道尽快。 这意味着在使用任何之前 exec*() 特别是一系列的职能。

经验法则还包括使用 dup() 要么 fcntl()F_DUPFD

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

#define EOL '\n'

int main(int argc, char *argv[])
{
    int tube1[2];   // Parent -> child
    int tube2[2];   // Child -> parent

    if (argc != 2)
    {
        perror("./yourProgram.c origin");
        exit(EXIT_FAILURE);
    }

    pipe(tube1);
    pipe(tube2);

    if (fork() == 0)
    {
        // Child Process

        dup2(tube1[0], 0);  // stdin ----> pipe reading end
        close(tube1[0]);    // reading end of the pipe to child
        close(tube1[1]);    // writing end of the pipe to child

        dup2(tube2[1], 1);  // stdout ---> pipe writing end
        close(tube2[0]);    // reading end of the pipe to parent
        close(tube2[1]);    // writing end of the pipe to parent

        // Execute and write the output in the tube2
        execlp("bc", "bc", "-q", NULL);
        perror("bc");
        exit(EXIT_FAILURE);
    }
    else
    {
        // Parent Process
        close(tube1[0]); // reading end of the pipe to child
        close(tube2[1]); // writing end of the pipe to parent

        // Files
        // Destiny
        char *destiny = "final.txt";
        int destinyFile = open(destiny, O_WRONLY | O_CREAT | O_TRUNC, 0644);
        if (destinyFile < 0)
        {
            perror(destiny);
            exit(EXIT_FAILURE);
        }

        // Origin
        char *origin = argv[1];
        int originFile = open(origin, O_RDONLY);
        if (originFile < 0)
        {
            perror(origin);
            exit(EXIT_FAILURE);
        }

        // Variables
        char block;
        char result;
        char buffer[256];
        int i = 0;
        int numbytes;

        while ((numbytes = read(originFile, &block, sizeof(block))) > 0)
        {
            buffer[i++] = block;
            //printf("Block: [%.*s]\n", i, buffer);
            if (block == EOL)
            {
                // Write on the tube, so the child can read it
                if (write(tube1[1], buffer, i) == -1)
                {
                    perror("error en write en pipe");
                    exit(EXIT_FAILURE);
                }
                buffer[i-1] = '\0';

                // Read the child's answer
                int j = 0;
                char reply[256];
                while ((numbytes = read(tube2[0], &result, sizeof(result))) > 0)
                {
                    reply[j++] = result;
                    //printf("Reply: [%.*s]\n", j, reply);
                    if (result == EOL)
                    {
                        // Concatenate strings as: 'X + Y = Result \n'
                        char str[256];
                        str[0] = '\0';
                        strcat(str, buffer);
                        strcat(str, " = ");
                        strcat(str, reply);

                        // Write the result in the Final File
                        if (write(destinyFile, str, strlen(str)) == -1)
                        {
                            perror("error en write en stdout");
                            exit(EXIT_FAILURE);
                        }
                        printf("Response: [%.*s]\n", j-1, reply);
                        break;
                    }
                }

                // Reset Buffer
                i = 0;
            }
        }
        close(tube1[1]);
        close(tube2[0]);
    }
    return 0;
}

给出样本输入文件:

2+3
4*5
8/2
quit

屏幕上的输出是:

Response: [5]
Response: [20]
Response: [4]

final.txt中的输出为:

2+3 = 5
4*5 = 20
8/2 = 4