简体   繁体   English

没有从管道中获得所有管线

[英]Not getting all the lines from a pipe

I'm working on an assignment in which I need a few processes (parent and children) to communicate. 我正在做一个作业,需要一些流程(父母和孩子)进行沟通。 The parent sends file paths to the children, and they have to run the linux file (/usr/bin/file) on them, returning the output to the father. 父级将文件路径发送给子级,并且子级必须在子级上运行linux file (/ usr / bin / file),并将输出返回给父级。

For now I'm still trying to get one child to work, so for now I assume there's one child. 目前,我仍在努力让一个孩子上班,所以现在,我假设有一个孩子。

I'm intend to send multiple file paths to each child (a batch of files), and then read file 's output. 我打算将多个文件路径发送给每个孩子(一批文件),然后读取file的输出。

The problem: 问题:

I use a loop to write a few file paths, but when I read the child's output pipe I don't get all the output I'm supposed to. 我使用循环来write一些文件路径,但是当我read孩子的输出管道时,并没有得到我应该得到的所有输出。

The code: 编码:

#define Read            0
#define Write           1
#define ParentRead      read_pipe[0]
#define ParentWrite     write_pipe[1]
#define ChildRead       write_pipe[0]
#define ChildWrite      read_pipe[1]
#define PIPE_BUF_LEN    4096

using namespace std;
int main()
{
    /** Pipe for reading for subprocess */
    int read_pipe[2];
    /** Pipe for writing to subprocess */
    int write_pipe[2];
    char buffer[PIPE_BUF_LEN] = "";
    if (pipe(read_pipe) == 0 && pipe(write_pipe) == 0)
    {
        pid_t pid = fork();
        if (pid == -1)
        {
            fprintf(stderr, "Fork failure");
            exit(EXIT_FAILURE);
        }
        else if (pid == 0) //Child process
        {
            close(ParentRead);
            close(ParentWrite);
            dup2 (ChildRead, STDIN_FILENO); /*redirect ChildRead to stdin*/
            dup2 (ChildWrite, STDOUT_FILENO); /*redirect stdout to ChildWrite*/
            char* paramArgs[]={"/usr/bin/file","-n","-f-",NULL};
            execv("/usr/bin/file",paramArgs);
            exit(EXIT_FAILURE);
        }
        else { //Parent process
            close(ChildRead);
            close(ChildWrite);

            for (int i=0; i < 3 ;i++)
            {
                /*write to processes which are ready for writing: */
                fd_set rfds;
                int retval;
                FD_ZERO(&rfds);
                FD_SET(ParentWrite, &rfds);
                retval = select(10, NULL, &rfds, NULL, NULL);
                if (retval == -1)
                {
                    perror("select()");
                }
                else if (retval)
                {
                    write(ParentWrite, "file1\nfile2\n", 12);
                }
                /*read from processes which are ready for reading*/
                FD_ZERO(&rfds);
                FD_SET(ParentRead, &rfds);
                retval = select(10, &rfds, NULL, NULL, NULL);
                if (retval == -1)
                {
                    perror("select()");
                }
                else if (retval)
                {
                    read(ParentRead, buffer, PIPE_BUF_LEN);
                    cout << buffer;
                }
            }
        }
    }
    exit(EXIT_SUCCESS);
}

In this case, I try to run file on "file1\\nfile2\\n" (notice the -n -f- flags used) in a loop of 3 iteration, expecting to get six lines, but get only three: 在这种情况下,我尝试在3次迭代的循环中在“ file1 \\ nfile2 \\ n”上运行file (注意使用了-n -f-标志),期望得到六行,但仅得到三行:

file1: ERROR: cannot open `file1' (No such file or directory) file1:错误:无法打开`file1'(没有这样的文件或目录)

file2: ERROR: cannot open `file2' (No such file or directory) file2:错误:无法打开`file2'(没有这样的文件或目录)

file1: ERROR: cannot open `file1' (No such file or directory) file1:错误:无法打开`file1'(没有这样的文件或目录)

When I don't redirect the child's output to the pipe (letting it write to the std_out), I do get all six lines. 当我不将孩子的输出重定向到管道(将其写入std_out)时,我确实得到了全部六行。

Any help will be appreciated. 任何帮助将不胜感激。

The scheduler. 调度程序。 You are in a loop that asks the child (ie the pgm file ) to look up two files three times. 您处于一个循环中,要求孩子(即pgm file )三遍地查找两个文件。 You only do one read per loop in the parent. 您只能在父级的每个循环中读取一次。

  • If the child is scheduled and uninterrupted it performs the first file lookup, writes the pipe, does the second lookup, writes to the pipe. 如果子进程已调度且不间断,则它将执行第一个文件查找,写入管道,执行第二次查找,写入管道。 Parent gets scheduled and you read the full output of the child in one read. 父母安排好了,您一次阅读了孩子的全部输出。 You are golden (but lucky). 你是金色的(但很幸运)。
  • The child is scheduled, does the first lookup and pipe write and gets interrupted. 子进程已安排好,进行第一次查找和管道写入并被中断。 The parent reads one output. 父级读取一个输出。 The child gets rescheduled and does the 2nd lookup and writes the pipe. 子级被重新安排并进行第二次查找并写入管道。 The parent reads one output. 父级读取一个输出。 Because you only read 3 times you end up only reading 3 of the 6 outputs. 因为您只读取3次,所以最终只能读取6个输出中的3个。
  • Variations on the above. 上面的变化。 Maybe you'll read 1 output then 3 then 1. You just don't know. 也许您会读到1个输出,然后读3个,然后读1个。您只是不知道。

Note that the reason you are at least getting a full child output on each read is because pipe writes are guaranteed to be atomic if they under PIPE_BUF length, which these are. 请注意,至少每次读取都获得完整的子级输出的原因是,如果管道写操作的长度小于PIPE_BUF,则保证它们是原子的。 If you were using this kind of a routine on, say a socket, you may end up getting some fractional portion of a message on each read. 如果在套接字上使用这种例行程序,则每次读取时最终可能会得到消息的一部分。

Solution: You have to read in a loop until you have the number of bytes (or full message) that you expect. 解决方案:您必须循环阅读,直到获得所需的字节数(或完整消息)为止。 In this case I assume the output of file is always one string ending in a newline. 在这种情况下,我假设file的输出始终是一个以换行符结尾的字符串。 But you are asking for two file outputs each time through the loop. 但是您每次通过循环都要求两个file输出。 So read until that condition is met, namely until you read two full strings. 因此,请阅读直到满足该条件为止,即直到您阅读了两个完整的字符串。

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

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