C中简单管道通信的问题

时间:2010-10-31 06:39:03

标签: c linux

我的练习有问题:

在C中编写一个创建子项的程序,在父与子之间,将使用管道进行双向通信。他的父亲将阅读一个文件(其名称将被提供给用户),并将向孩子发送信件。

孩子将使用'a'计算从开始的单词数;如果数字是,是否X的单词,X,以'a'开头大于5,那么孩子将创建自己的孩子(孙子)。企业的孙子将以您认为可能的方式发送X 数字的祖父 * 并退出。 [通过推论:如果数字X小于6,那么孩子就会退出,而'将是祖父母'也会退出。]

  • 注意:爷爷=父亲的初始过程,即他父亲的孙子的父亲

这是我到目前为止所做的事情;请帮帮我......

#include <stdio.h>
#include<string.h>
#include <stdlib.h>
#include <fcntl.h>
int main(int argc, char *argv[]) 
{ 
 int fd1[2], fd2[2], pid, status,sum=0, i;
 char gram[100], x;
 char buff[100];
 char rev[1000];
FILE *fp;
 if (pipe(fd1) == -1) { /* Create a pipe */
  perror("pipe");
  exit(1);
 }
 pid = fork();
 switch (pid)
  { 
 case -1:
  perror ("Fork error\n");
  exit(99); // in case of error
 case 0:
  close(fd1[1]);//Close the writing side 

  rev[1000]= read(fd1[0], buff, 1000); /* Read from the pipe */
  /*for (i=0; i< 1000 ; i++)
  {
   rev[i] = read(fd1[0], buff, sizeof(buff));
  }*/

   while( rev[i] != '\0')
   { 
    if (buff[i] == 'a' )
    {  sum++;
      i++;
    }  
    if (rev[i] == "")
    {

     if (rev[i+1]) //elenxei to epomeno tou kenou
     {
      sum++;
      i++;
     }
    }
    i++;
   }
   printf("%d", sum);

  exit(0);
 default:
  printf("dwse arxeio\n");
  scanf("%s", gram);
  close(fd1[0]);//Close the reading side
  fp = fopen (gram,"r"); 
  getc(fp);
  fclose(fp);
  write(fd1[1], buff, sizeof(buff)+1);
  close(fd1[1]);//Close the writing side
  wait(&status); // waits till the child process  ends
 } 
}

3 个答案:

答案 0 :(得分:1)

您可能希望查看popen。 它启动一个子进程并返回一个FILE *,你可以使用它来读取/写入childs stdin / stdout。

答案 1 :(得分:1)

让我们调用GP(对于祖父母),PP(对于父进程)和GC(对于孙子)这三个进程。概括地说,我认为你需要做的是:

  1. GP创建两个指定RP(读取管道)和WP(写入管道)的管道(4个文件描述符)。这描述了GP将如何使用它们; PP和GC将在RP上书写并在WP上阅读。
  2. GP分叉,创造PP。
  3. GP将关闭RP的写入结束和WP的读取结束。
  4. GP将打开该文件。
  5. GP将通过WP编写适合PP的文件的任何子集。
  6. 当没有更多数据要传输时,GP将关闭WP。
  7. GP也应该关闭它打开的文件。
  8. GP将从RP读取,可能会将数据存储起来,直到获得EOF。
  9. 如果收到任何信息,GP会将该信息回显给标准输出。
  10. GP可以终止。
  11. 与此同时,上面的第2步创建了PP,他必须做一些工作:

    1. PP需要关闭RP的读取端和WP的写入端。
    2. PP处于循环中,从WP读取数据,计算相关的数据。
    3. 当PP在WP上获得EOF时,它可以决定它需要做什么。
    4. PP现在可以关闭WP的读取结束。
    5. 如果它的计数器X大于5,那么(由于只在家庭作业中有意义的原因)它会分叉以创建GC;它可以退出。
    6. 如果其计数器X没有达到阈值,那么就规范而言,它可以立即终止。对于调试,你可能会在stdout上打印一些关于它的作用和原因。
    7. 现在你有GP和GC了;请记住,GC几乎是PP的精确副本,并且(特别是)GC和PP一样知道X的值。所以,GC也做了一些工作:

      1. GC将X格式化为字符串(可能 - 如果您愿意,可以进行二进制数据传输,但是将格式化降压传递给GP,这就是全部。)
      2. GC将格式化的X写入RP的写入端。
      3. GC关闭RP的写入结束。
      4. GC退出。
      5. GC的第3步确保GP从第8步中醒来。

        作为工业设计,没有必要创建GC; PP可以很好地完成GC的工作。作为一项家庭作业,它通过了集合。关键的见解在上面的评论中:

          

        问题的关键在于如何从孙子到祖父的沟通。好消息是,孙子继承了孩子们打开的管道。

        其他关键步骤是关闭管道未使用的末端并关闭管道,此时无需再编写。没有这些关闭,进程很容易陷入死锁。例如,如果GP无法关闭RP的写入端,那么从RP读取时它永远不会获得EOF,因为有一个进程仍然可以写入RP - 而且该进程是GP!

答案 2 :(得分:0)

rev[1000]= read(fd1[0], buff, 1000); /* Read from the pipe */

你想用左值来完成什么?

首先,rev被声明为具有1000个元素,因此rev[1000]是缓冲区溢出...

其次,我建议您查看read()手册页的“返回值”部分。它返回接收的字节数(可能小于您指定的第三个参数),或者在文件结束时为0,或者在失败时为负。它将使用实际数据填写buff的内容。我不确定你的代码中你期望系统调用的行为是什么,但在我看来并不像你正确使用它。

你想做这样的事情:

int r;

r = read(fd1[0], buff, sizeof(buff));
if (r < 0)       { /* TODO: Handle error */ }
else if (r == 0) { /* TODO: Handle EOF */ }
else             { /* TODO: Handle the fact that buff now contains 'r' bytes */ }