2

コマンドラインから子プロセスにパイプ送信ファイル名を作成するプログラムを作成する必要があります。子でそのファイルを読み取り、パイプを使用して送り返します。親プロセスはファイルを印刷する必要があります。子プロセスでエラーが発生した場合、親プロセスにエラーを送信する必要があります。

これが私のコードです。ファイルファイルに沿っていくつかのジャンクを出力します(また、実行時にターミナルエミュレータでスクロールを無効にします)。

#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);
}
4

3 に答える 3

2

それよりも少ない値が返されたsizeof(buf)場合、意味のあるバイトを書き込むことはできません。fgets残りはがらくたでいっぱいになります。

さらに、文字列指向fgetsとバイナリを混在させるread/writeのは悪いスタイルです。readまたはを使用freadしてファイルを読み取ります。読み取ったバイト数を返します。この数値を への引数として使用しますwrite

于 2012-04-13T11:05:57.527 に答える
2

かなりの変更を加えた後、プログラムは意図したとおりに動作します。すべての変更が必要な理由とその理由をリストアップしましょう。

I) 子と親の両方で、使い終わったらすぐにそれぞれのパイプを閉じます。のマニュアルページからread(3)

一部のプロセスがパイプを書き込み用に開いていて、O_NONBLOCK がクリアされている場合、read() は、一部のデータが書き込まれるか、書き込み用にパイプが開いているすべてのプロセスによってパイプが閉じられるまで、呼び出しスレッドをブロックします。

したがって、ジョブ パイプが終了したすべての場所で、コード内で次のようなことを行います。

  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複数回返されると爆撃bufferし、プロセス中に毎回上書きします

ファイルから読み取るには、常に単純な組み合わせを使用fgetcします。feofしたがって、ファイル読み取りメカニズムを次のように変更します

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)子からファイル データを書き込んでいる間は、(バッファが null で終了していることを既に確認しているため、上記を参照) を使用する必要が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:ファイルの読み取りロジックを変更したため、コンパイラエラーはなくなり、nmのアドバイスに従ってください。

于 2012-04-13T12:24:38.940 に答える
0

このコードはコンパイルされません:

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

elseそこに句を入れることはできません。

于 2012-04-13T11:02:46.643 に答える