使用未命名的管道发送信息

时间:2018-04-18 19:16:47

标签: c linux pipe

我的程序必须使用未命名的管道发送一些字节的信息。 我有一个名为“input”的txt文件,它应该被程序读取,并且它的信息必须在另一个名为“output”的文件中发送和写入。我还必须使用read(),write(),open()函数。 我的代码看起来像这样:

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <time.h>
#include <string.h>
#define BUFSIZE 25

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

    srand(time(NULL));
    pid_t pid;
    int mypipefd[2];
    int ret;
    char buf[BUFSIZE];
    int output;
    int stream;
    int nbytes;
    ret = pipe(mypipefd);

    if( ret == -1 ) {
        perror( "pipe error");
        exit(1);
    }
    pid = fork();

    if( pid == -1 ) {
        perror( "FORK ERROR...");
        exit(2);
    }
    if( pid == 0 ) {
        /* CHILD */
        printf(" Child process...\n");
        stream = open("input.txt", O_RDONLY);
        if (close(mypipefd[0]) == -1 ) {
            perror("ERROR CLOSING PIPE");
            exit(3);
        }
        while ( (nbytes = read(stream, buf, BUFSIZE)) > 0 ) {
            sleep(rand() %2);
            write(mypipefd[1], buf, nbytes );
        }
        if ( close(stream) == -1 ) {
        perror("ERROR CLOSING STREAM");
        exit(4);
        }
    }
    else {
        /* PARENT */
        printf(" Parent process...\n");
        output = open("output.txt", O_CREAT | O_WRONLY, 00777);
        while ( (nbytes = read(mypipefd[0], buf, BUFSIZE)) > 0 ) {
            write(output, buf, nbytes);
        }
        printf("buf: %s\n", buf);
        if (close(output) == -1) {
            perror("ERROR CLOSING OUTPUT");
            exit(5);
        }
        if (close(mypipefd[1]) == -1 ) {
            perror("ERROR CLOSING PIPE");
            exit(6);
        }
    }


    return 0;

}

不幸的是,代码无效terminal screen

在我尝试while循环并一次发送所有信息之前,它有效,但输出文件看起来像这样output file

虽然输入文件看起来像input file

1 个答案:

答案 0 :(得分:1)

主要错误是必须在父读取循环之前执行close(mypipefd[1]) (并且之后不)。在孩子完成写作后,这会阻止父母在管道上看到EOF。

此外,您错过了父母的waitpid

父级printf的{​​{1}}位于错误的位置[读取循环之后]。此时,buf无法保证拥有正确的数据,或者它已正确终止。这就是为什么stdout最后会有一些垃圾字符。

因此,除了输出到输出文件之外,循环应该输出到stdout,但是应该使用buf,因为fwrite不能保证零终止。

我在最初的帖子中错过了,所以我已经纠正了它。

根据我的最高评论,孩子应该循环[可能]部分写入管道。我把它编码了。

这里是带有注释和修复错误的版本:

buf

<强>更新

  

但我不明白&#34;对于&#34;循环做到这里

写入管道可以生成&#34;短写入&#34; (例如,您希望写入20但返回值(即实际写入的字节数)返回15.您必须索引到缓冲区并在后续写入中写入剩余的字节。

在单个原子写入中可以写入多少字节的内核限制(例如)如果你做#include <stdlib.h> #include <stdio.h> #include <unistd.h> #include <string.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <time.h> #include <string.h> #include <sys/types.h> #include <sys/wait.h> #define BUFSIZE 25 int main( int argc, char *argv[] ) { srand(time(NULL)); pid_t pid; int mypipefd[2]; int ret; char buf[BUFSIZE]; int output; int stream; int nbytes; ret = pipe(mypipefd); if( ret == -1 ) { perror( "pipe error"); exit(1); } pid = fork(); if( pid == -1 ) { perror( "FORK ERROR..."); exit(2); } if( pid == 0 ) { /* CHILD */ printf(" Child process...\n"); stream = open("input.txt", O_RDONLY); if (close(mypipefd[0]) == -1 ) { perror("ERROR CLOSING PIPE"); exit(3); } while ( (nbytes = read(stream, buf, BUFSIZE)) > 0 ) { sleep(rand() %2); #if 0 write(mypipefd[1], buf, nbytes ); #else // NOTE: this _should_ work but adds extra at the end int off; int wlen; for (off = 0; nbytes > 0; off += wlen, nbytes -= wlen) { wlen = write(mypipefd[1], buf + off, nbytes ); if (wlen <= 0) break; } #endif } if ( close(stream) == -1 ) { perror("ERROR CLOSING STREAM"); exit(4); } // NOTE/FIX: child must close it's side of the pipe #if 1 close(mypipefd[1]); #endif } else { /* PARENT */ printf(" Parent process...\n"); // NOTE/FIX: this must be closed _before_ the read loop -- holding it // open prevents parent from seeing EOF on pipe #if 1 if (close(mypipefd[1]) == -1 ) { perror("ERROR CLOSING PIPE"); exit(6); } #endif #if 1 printf("buf: "); #endif output = open("output.txt", O_CREAT | O_WRONLY, 00777); while ( (nbytes = read(mypipefd[0], buf, BUFSIZE)) > 0 ) { write(output, buf, nbytes); #if 1 fwrite(buf,1,nbytes,stdout); #endif } // NOTE/BUG: the buffer at this point will only have the data from // the _last_ read and may not be null terminated #if 0 printf("buf: %s\n", buf); #else printf("\n"); #endif if (close(output) == -1) { perror("ERROR CLOSING OUTPUT"); exit(5); } // NOTE/BUG: this must be closed _before_ the parent's read loop #if 0 if (close(mypipefd[1]) == -1 ) { perror("ERROR CLOSING PIPE"); exit(6); } #endif // NOTE/FIX: this is missing (prevents orphan/zombie child process) #if 1 waitpid(pid,NULL,0); #endif } return 0; } ,内核没有为这么大的写分配空间,所以它将返回它可以附加到管道缓冲区[在内核中]的值。

另外,让我们说内核管道缓冲区可以容纳64个字节。然后你写了大小为64的缓冲区。也许读者只读32个字节。所以,第一次写就好了。然后读者读出32个字节。因此,下一次写入64管道时,只有32字节的空间,因此写入将返回32

  

程序必须显示:&#34; buf:这是ra&#34;那么&#34; buf:ndom text&#34;

好的,我已经修好了

  

最后,我需要在任何地方实现错误处理。

我注释了我添加错误和处理的地方,以及一些要查找的内容。

无论如何,这是一个更新版本。我已经在write(mypipefd[1],buf,10000000)条评论中删了,但删除了// NOTE/*对以便于阅读。

#if/#endif