0

親プロセスと子プロセス間の通信にLinuxで通常のパイプラインを使用する方法を学んでいます。基本的なタスクは、親プロセスから子プロセスにメッセージを送信するだけで、子プロセスは何らかの変換を行い、結果を親プロセスに返します。表示される結果は、��� のようなランダムな文字です。私は長い間考えていましたが、まだバグを理解できませんでした。ご協力いただきありがとうございます。

#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>

#define READ_END 0
#define WRITE_END 1

void convert(char* str);

int main(int argc, char *argv[]){
  int pid; /* Process ID */
  int status;
  char *input;
  char *read_msg_c;
  char *read_msg_p;
  int pfd1[2], pfd2[2];
  if (argc !=2){/* argc should be 2 for correct execution */
    /* We print argv[0] assuming it is the program name */
    printf("Please provide the string for conversion \n");
    exit(-1);
  }
  input = argv[1];

  if(pipe(pfd1) < 0 || pipe(pfd2) < 0){
    printf("Failed to create a pipe between parent and child \n");
    exit(-1);
  }
  if((pid = fork()) < 0){ /* Fork the process */
     printf("Fork error \n");
     exit(-1);
  }
  else if(pid > 0){ /* Parent code */
    close(pfd1[READ_END]);
    close(pfd2[WRITE_END]);
    printf("Process ID of the parent is %d. \n", getpid()); /* Print parent's process ID */
    write(pfd1[WRITE_END],input,strlen(input)+1);
    close(pfd1[WRITE_END]);

    read(pfd2[READ_END],read_msg_p,strlen(input)+1);
    printf("%s\n",read_msg_p);
    close(pfd2[READ_END]);
  }
  else if(pid == 0){ /* Child code */
    close(pfd1[WRITE_END]);
    close(pfd2[READ_END]);

    printf("Process ID of the child is %d. \n", getpid()); /* Print child's process ID */
    read(pfd1[READ_END],read_msg_c, strlen(input)+1);
    printf("Child: Reversed the case of the received string. \n");
    write(pfd2[WRITE_END],read_msg_c,strlen(input)+1);
    close(pfd1[READ_END]);
    close(pfd2[WRITE_END]);
    exit(0); /* Child exits */
   }
}

void convert(char *str){
  int i = 0;
  while (str[i]){
    if (isupper(str[i])){
      str[i] = tolower(str[i]);
    }
    else if (islower(str[i])){
      str[i] = toupper(str[i]);
    }
    i++;
  }
}
4

1 に答える 1

2

あなたの主なバグは、変数read_msg_pread_msg_cが初期化されていないポインターであることです。

それらを配列にします:

char read_msg_p[1024];
char read_msg_c[1024];

行方不明のようです<stdio.h>(ただし、これ以上は必要ありません<sys/types.h>)。読み取りと書き込みをエラーチェックする必要があります。読み取り用のスペースを割り当てたら、おそらく別の最大サイズを使用するでしょう。等。

コンパイラの警告を見て、問題を見つけました。

$ gcc -O3 -g -std=c99 -Wall -Wextra pipes-14420398.c -o pipes-14420398
pipes-14420398.c: In function ‘main’:
pipes-14420398.c:40:22: warning: ‘read_msg_p’ may be used uninitialized in this function [-Wuninitialized]
pipes-14420398.c:52:22: warning: ‘read_msg_c’ may be used uninitialized in this function [-Wuninitialized]
$

行番号は無視してください。これらの警告が残っているだけになるまでに、私はあなたのコードを適度に真剣にハッキングしました。しかし、問題の行はread()呼び出しです。


ハッキングされたコードからの出力例。正常に動作しています。

$ ./pipes-14420398 string-to-convert
Process ID of the parent is 37327. 
Process ID of the child is 37328. 
Child read 18 bytes: <<string-to-convert>>
Parent read 18 bytes: <<string-to-convert>>
$

nbytes-1以下のコードは 18 バイト (null を含む) を読み取りますが、null を出力しないことに注意してください ( printf().

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

#define READ_END 0
#define WRITE_END 1


int main(int argc, char *argv[])
{
  int pid; /* Process ID */
  char *input;
  char read_msg_c[1024];
  char read_msg_p[1024];
  int pfd1[2], pfd2[2];

  if (argc !=2){/* argc should be 2 for correct execution */
    /* We print argv[0] assuming it is the program name */
    fprintf(stderr, "Usage: %s string-to-convert\n", argv[0]);
    exit(-1);
  }
  input = argv[1];

  if(pipe(pfd1) < 0 || pipe(pfd2) < 0){
    printf("Failed to create a pipe between parent and child \n");
    exit(-1);
  }
  if((pid = fork()) < 0){ /* Fork the process */
     printf("Fork error \n");
     exit(-1);
  }
  else if(pid > 0){ /* Parent code */
    close(pfd1[READ_END]);
    close(pfd2[WRITE_END]);
    printf("Process ID of the parent is %d. \n", getpid()); /* Print parent's process ID */
    write(pfd1[WRITE_END], input, strlen(input)+1);
    close(pfd1[WRITE_END]);

    int nbytes = read(pfd2[READ_END], read_msg_p, sizeof(read_msg_p));
    if (nbytes <= 0)
        printf("Parent: read failed\n");
    else
        printf("Parent read %d bytes: <<%.*s>>\n", nbytes, nbytes-1, read_msg_p);
    close(pfd2[READ_END]);
  }
  else if(pid == 0){ /* Child code */
    close(pfd1[WRITE_END]);
    close(pfd2[READ_END]);

    printf("Process ID of the child is %d. \n", getpid()); /* Print child's process ID */
    int nbytes = read(pfd1[READ_END], read_msg_c, sizeof(read_msg_c));
    if (nbytes <= 0)
        printf("Child: read failed\n");
    else
    {
        printf("Child read %d bytes: <<%.*s>>\n", nbytes, nbytes-1, read_msg_c); 
        write(pfd2[WRITE_END], read_msg_c, nbytes);
    }
    close(pfd1[READ_END]);
    close(pfd2[WRITE_END]);
    exit(0); /* Child exits */
   }
}

WhozCraigが指摘したように、他にも多くの変更を加えることができます。ただし、これにより、物事が合理的にきれいに機能します。あなたはOKに非常に近かった。

デバッグ手法に注意してください。

  1. 高い警告レベルでコンパイルし、すべての警告を修正します。
  2. 利用可能になった情報を出力します (または、デバッガーで実行して、利用可能になった情報を観察します)。
于 2013-01-20T00:37:24.223 に答える