[C] Pipes unter Linux

Rene Albrecht

Erfahrenes Mitglied
Hallo,

ich versuche gerade, mich in die Interprozesskommunikation per Pipes einzuarbeiten und stosse auf ein (wahrscheinlich einfaches) Problem: Ein Programm namens child2 gibt etwas über stdout aus, dass ich durch ein Programm parent auslesen möchte. Folgende Code funktioniert leider nicht:
Code:
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>

#define MAX 512

int main(void) {
   int p2c[2];
   pid_t pid;
   char buffer[512];
   int n;

   pipe(p2c);

   pid = fork();
   if (pid == -1) {
      fprintf(stderr,"Fehler: fork()\n");
      exit (1);
   }

   if (pid == 0) {                  // Kindprozess
      dup2(p2c[1],1);
      close(p2c[0]);
      execlp("child2","child2",NULL);
   }
   else {                           // Vaterprozess
      close(p2c[1]);
      n=read(p2c[0],&buffer,512);
      printf("%d Zeichen gelesen\n",n);
      close(p2c[0]);
      wait(0);
   }
   exit (0);
}

Kann mir jemand erklären, warum das so nicht funktioniert?

Gruß
René
 

RedWing

Erfahrenes Mitglied
Hallo,

also dein Beispiel funktioniert bei mir.

Bist du dir auch sicher das dein Programm "child2" im PATH ist?

Gruß,
RedWing
 

Rene Albrecht

Erfahrenes Mitglied
Code:
renalb@fileserver:~$ ls -al
insgesamt 56
drwxr-xr-x 3 renalb users 4096 2007-09-05 21:38 .
drwxr-xr-x 4 root   root  4096 2007-08-29 15:48 ..
-rw------- 1 renalb users 1976 2007-08-29 18:50 .bash_history
-rw-r--r-- 1 renalb users  220 2007-08-29 15:48 .bash_logout
-rw-r--r-- 1 renalb users  413 2007-08-29 15:48 .bash_profile
-rw-r--r-- 1 renalb users 2221 2007-08-29 15:48 .bashrc
-rwxr-xr-x 1 renalb users 8015 2007-09-05 21:27 child2
-rw-r--r-- 1 renalb users  481 2007-09-05 21:27 child2.c
drwxr-xr-x 2 renalb users 4096 2007-08-29 18:24 .mc
-rwxr-xr-x 1 renalb users 8151 2007-09-05 21:38 parent
-rw-r--r-- 1 renalb users  614 2007-09-05 21:37 parent.c
-rwxrw-rw- 1 renalb users  164 2007-08-29 18:33 test.bash
"child2" ist im gleichen Verzeichnis wie parent.

Trotzdem bekomme ich das:
Code:
renalb@fileserver:~$ ./parent
0 Zeichen gelesen
renalb@fileserver:~$
:confused:

@RedWing: Was kommt bei Dir raus?

Achso, mein child2.c sieht so aus (sorry für die Form, musste schnell gehen):
Code:
#include <stdio.h>
#include <unistd.h>

int main(void) {
   char s[256];
   fprintf(stdout,"Ausgabe 1 auf stdout\n");
   fprintf(stderr,"Ausgabe 1 auf stderr\n");
   sleep(10);
   fprintf(stdout,"Ausgabe 2 auf stdout\n");
   fprintf(stderr,"Ausgabe 2 auf stderr\n");
   sleep(10);
   fprintf(stdout,"Ausgabe 3 auf stdout\n");
   fprintf(stderr,"Ausgabe 3 auf stderr\n");
   fprintf(stdout,"Tippst du: "); scanf("%s",s);
   fprintf(stdout,"Getippt hast du: %s\n",s);
   exit (0);
}
 

RedWing

Erfahrenes Mitglied
Hi!

Code:
renalb@fileserver:~$ ls -al
insgesamt 56
drwxr-xr-x 3 renalb users 4096 2007-09-05 21:38 .
drwxr-xr-x 4 root   root  4096 2007-08-29 15:48 ..
-rw------- 1 renalb users 1976 2007-08-29 18:50 .bash_history
-rw-r--r-- 1 renalb users  220 2007-08-29 15:48 .bash_logout
-rw-r--r-- 1 renalb users  413 2007-08-29 15:48 .bash_profile
-rw-r--r-- 1 renalb users 2221 2007-08-29 15:48 .bashrc
-rwxr-xr-x 1 renalb users 8015 2007-09-05 21:27 child2
-rw-r--r-- 1 renalb users  481 2007-09-05 21:27 child2.c
drwxr-xr-x 2 renalb users 4096 2007-08-29 18:24 .mc
-rwxr-xr-x 1 renalb users 8151 2007-09-05 21:38 parent
-rw-r--r-- 1 renalb users  614 2007-09-05 21:37 parent.c
-rwxrw-rw- 1 renalb users  164 2007-08-29 18:33 test.bash
"child2" ist im gleichen Verzeichnis wie parent.

Wirf mal einen Blick in die exec* man-page. Da steht unter anderem für execpl:
The functions execlp() and execvp() will duplicate the actions of the shell in searching for an executable file if the specified filename does not contain a slash (/) character. The search path is
the path specified in the environment by the PATH variable. If this variable isn’t specified, the default path ‘‘:/bin:/usr/bin’’ is used. In addition, certain errors are treated specially.

d.h. dein Programm sollte schon in $PATH irgendwo liegen. (also entweder /usr/bin oder /bin, etc).

Damit dir sowas kein 2. mal passiert solltest du dir angewöhnen etwas defensiver zu programmieren, d.h. den return Code eines System calls abfragen und entsprechend auf Fehler reagieren:
C:
int main(void)
{
...
   if (pid == 0) {                  // Kindprozess
      dup2(p2c[1],1);
      close(p2c[0]);
      if (execlp("adsf", NULL) == -1) {
          perror ("Error in execlp()");
          return 1;
      }
      /* we should never get here! */
   }
...
}

Gruß,
RedWing
 

Rene Albrecht

Erfahrenes Mitglied
Du hattest Recht, jetzt funktionierts...

Noch eine Frage zu Pipes: Kann ich auch - ohne Eröffnen einer zweiten Pipe - stdin UND stderr umleiten, so dass ich beide Kanäle verarbeiten kann?