2012-04-13 29 views
1

我需要编写一个程序,创建管道发送文件名从命令行到子进程。在孩子读取该文件并使用管道将其发回。父进程应该打印文件。如果在子进程中发生错误,必须将错误发送给父进程。程序读取文件并将其发送到父进程与管道

这里是我的代码,它沿着文件文件打印一些垃圾(当它运行时它也禁用终端模拟器中的滚动)。

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

void main(int argc, char *argv[]) { 
    int pipefd[2]; 
    char buff[100]; 
    int childpid; 
    int size; 
    FILE *file; 

    if (argc != 2) { 
     printf("usage:\n%s <filename>\n", argv[0]); 
     exit(1); 
    } 
    if (pipe(pipefd) < 0) { 
     perror("can't open pipe\n"); 
    } 
    if ((childpid = fork()) == 0) { 
     sleep(1); 
     size = read(pipefd[0], buff, sizeof(buff)); 
     file = fopen(buff, "r"); 
     if (file == NULL) { 
     write(pipefd[1], "Can't open file", 15); 
     exit(1); 
     } 
     while (!feof(file)) { 
     if (fgets(buff, sizeof(buff), file) == NULL) { 
      write(pipefd[1], "Error reading file", 18); 
     } else { 
      write(pipefd[1], buff, sizeof(buff)); 
     } 
     } 
    } else if (childpid > 0) { 
     size = strlen(argv[1]); 
     if (write(pipefd[1], argv[1], size) != size) { 
     perror("Error writing to pipe\n"); 
     } 
     wait(NULL); 
     while ((size = read(pipefd[0], buff, sizeof(buff))) > 0) { 
     write(1, buff, size); 
     } 
    } 
    exit(0); 
} 
+0

它应该是'int main(int argc,char * argv [])''。 – 2012-04-13 10:55:52

+0

你能告诉我们你面临什么问题吗? – 2012-04-13 10:55:56

+0

如果文件足够大,则会导致死锁;父母等待孩子死亡,但孩子可能会等待父母读取管道。你假设双向管道;这些还不是标准的(尽管它们在Linux上是可用的,我相信)。当它完成写入时,你的父进程应该关闭其管道的写入端;可以说,孩子在完成阅读后应该关闭阅读器的读取端。 – 2012-04-13 10:59:57

回答

2

经过不少变更后,您的程序将按预期工作。让我们列出需要进行的所有更改以及为什么 -

I)无论是在孩子还是父母身上,只要您完成了这些操作,请关闭相应的管道。从read(3)man page

如果某些进程打开了写作的管道和O_NONBLOCK是清楚的, 阅读()应阻止调用线程,直到一些数据被写入或 管是由有所有进程关闭该管道打开为 写入。

所以做这样的事情在你的代码到处在作业的管道已经结束,

size = read(pipefd[0], buff, sizeof(buff)); 
    close(pipefd[0]); 

    write(pipefd[1], buff, strlen(buff)); 
    close(pipefd[1]); 

    if (write(pipefd[1], argv[1], size) != size) { 
    perror("Error writing to pipe\n"); 
    } 
    close(pipefd[1]); 

    while ((size = read(pipefd[0], buff, sizeof(buff))) > 0) 
    { 
    write(1, buff, size); 
    } 
    close(pipefd[0]); 

您还没有关闭的孩子管道的写端和您的父母被封堵在read

II)您正在使用类似while(fgets(...))在一个循环从文件中读取数据。 这将轰炸当有文件中的新行和fgets返回多次,过程

我总是用简单fgetcfeof组合从文件读取过程中覆盖buffer每次。因此,改变你的文件读取机制,像

unsigned count=0; 
while (!feof(file) && count < sizeof(buff)) 
    buff[count++]=fgetc(file); 
if (feof(file)) 
    buff[--count]=0; 
else 
    buff[sizeof(buff)-1]=0; 

III)虽然从孩子写的文件数据,你应该使用strlen(因为我们已经取得了一定缓冲空终止,见上)而不是sizeof,因为缓冲区可能不会充满,您最终会写入垃圾。因此,改变

write(pipefd[1], buff, sizeof(buff)); 

write(pipefd[1], buff, strlen(buff)); 

IV)按照从孩子和家长一个安全exit他们的工作完成之后。像

close(pipefd[1]); 
_exit(EXIT_SUCCESS); // in child 

close(pipefd[0]); 
exit(EXIT_SUCCESS); // in parent 

PS了一句:我已经修改了文件读取逻辑,所以你的编译错误,现在已经没有了,做遵循牛米给出的建议。

+0

并可能使用两个管道。在当前代码中,父级和子级都读取和写入同一个管道。 – JeremyP 2012-04-13 13:03:34

+0

不错的建议@JeremyP。尽管在当前的例子中它没有影响,但它是一件好事! – 2012-04-13 14:27:04

+0

要小心在主循环逻辑中使用'feof()'。通常使用'feof()'的唯一时间是错误处理代码,它需要在从诸如fgets()的函数获取问题指示后区分EOF和文件读/写错误。其他任何有点可疑。 – 2012-04-13 21:05:11

0

此代码不能编译:

while (fgets(buff, sizeof(buff), file) != NULL) { 
     write(pipefd[1], "Error reading file", 18); 
    } else { 
     write(pipefd[1], buff, sizeof(buff)); 
    } 

你不能有一个else条款存在。

+0

是的,我有,如果声明,但我删除它。 – jcubic 2012-04-13 20:43:15

+0

@jcubic:很难调试其他人的代码;调试不是他们正在运行的代码的东西要困难得多。了解如何将您的代码减少到最小化测试案例,以证明您的问题,并且可以将其粘贴到问题中。它应该尽可能短(但不能短于);一个目标应该是20-50行,如果有必要,更短更好更长时间,但如果它长于约100行,你可能没有把它最小化。是否可以删除任何行或声明? – 2012-04-13 21:03:10

+0

对不起,我刚更新了代码。我认为这个代码很小,不会缩小。而且我也认为这种代码对于了解C和Linux的人来说是微不足道的。 – jcubic 2012-04-13 21:17:55

2

如果fgets返回的值小于此值,则不能写入sizeof(buf)有意义的字节。其余的将充满垃圾。

此外,混合字符串为导向fgets与二进制read/write是一种不好的风格。使用readfread来读取文件。它们返回读取的字节数,将该数字用作参数write

相关问题