繁体   English   中英

用C语言进行简单管道通信的问题

[英]Problem with simple pipe communication in C

我对此练习有问题:

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

孩子将计算 'a'开始的单词数; 如果数字是,则以“a”开头的单词X是否大于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
 } 
}

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

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

  1. GP创建两个管道(4个文件描述符),指定RP(读取管道)和WP(写入管道)。 这描述了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然后可以终止。

同时,上面的第2步创建了PP,他必须做一些工作:

  1. PP需要关闭RP的读取端和WP的写入端。
  2. PP处于循环状态,从WP读取数据,对任何相关数据进行计数。
  3. PP在WP上获得EOF时,可以决定需要执行的操作。
  4. PP现在可以关闭WP的读取端。
  5. 如果它的计数器X大于5,那么(由于只在家庭作业中有意义的原因)它将分叉以创建GC; 然后可以退出。
  6. 如果其计数器X没有达到阈值,那么就规范而言,它可以立即终止。 为了进行调试,您可能会打印出一些东西以标出其功能和原因。

现在您有了GP和GC; 请记住,GC几乎是PP的精确副本,并且(特别是)GC和PP一样知道X的值。 所以,GC也做了一些工作:

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

GC的步骤3确保GP从其步骤8唤醒。

从工业设计的角度来看,创建GC是没有意义的。 PP可以很好地完成GC的工作。 作为一项家庭作业,它会通过鼓舞。 关键见解在上面的评论中:

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

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

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 */ }

暂无
暂无

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

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