C Prozesse mit Pipe verbinden

Wie man unter Linux eine Pipe zur Kommunikation zwischen zwei Prozessen benutzt.



Prozesse mit Pipe verbinden
Pipes werden dazu verwendet, um die Kommunikation zweier Prozesse zu gewährleisten. Pipes stellen also den Verbindungskanal zwischen zwei Prozessen her! In diesem Artikel erfahren Sie, wie eine >>namenlose Pipe<< und eine >>benannte Pipe<< erstellt werden kann.


Beschreibung verwendeter Systemfunktionen
>>dup2<<
dup2() ist eine Systemfunktion, welche in der File Descriptor Table einen offenen Dateideskriptor dupliziert. Es existiert auch eine Funktion dup() (hier nicht eingesetzt). Der Unterschied der Beiden Funktionen besteht darin, dass dup2() im Gegensatz zu dup() nicht unterbrechbar ist "atomar"

>>mkfifo<<
Mit mkfifo() kann eine benannte Pipe erstellt werden.

>>unlink()<<
unlink() Löscht vorhandene Verzeichniseinträge auf eine verweisende Datei. Existieren keine Einträge mehr, wird die Datei gelöscht


Namenlose Pipe
Vorgehensweise:

  1. Elternprozess muss die Funktion pipe() aufrufen, um eine Pipe zu erzeugen.
  2. Elternprozess erzeugt zwei Kindprozesse. Somit wird die >>File Descriptor Table<< mit allen Deskriptoren mit vererbt.
  3. Kindprozesse erzeugen über die Funktion dup2() einen neuen Eintrag in der >>File Descriptor Table<<
  4. Kindprozesse schließen mit der Funktion close() die Pipe.
  5. Kindprozesse können nun mittels den Funktionen write() in die Pipe schreiben, und mit read() geschriebene Daten wieder lesen.
int main( int argc, char **argv )
{
  int fileDescr[2]; // Zwei Dateideskriptoren anlegen
  char *message = "Hallo Welt\n"; // = 11 Zeichen
  char buffer[11]; // Platz für 11 Zeichen schaffen
  int status; // Endstatus
 
 
  // Pipe erzeugen
  pipe(fileDescr);
 
 
  // 1.Kind erzeugen --> Daten schreiben
  if( fork() == 0 )
  {
    dup2( fileDescr[1], 1 ); // Eingang der Pipe auf stdin legen
    close( fileDescr[0] ); // Ausgang der Pipe schliessen
    write(1, message, 11); // Daten schreiben (11 Zeichen auf Konsole)
  }
 
  // 2.Kind erzeugen --> Daten lesen
  else id( fork() == 0 )
  {
    dup2( fileDescr[0], 0 ); // Ausgang der Pipe auf auf stdout legen
    close( fileDescr[1] ); // Eingang der Pipe schließen
    read(0, buffer, 11);  // Daten lesen (11 Zeichen)
    printf("%s", buffer); // Gelesene Daten ausgeben
  }
 
  // Elternprozess
  else
  {
    // Pipes schliessen
    close( fileDescr[0] ); // Ausgang der Pipe
    close( fileDescr[1] );  // Eingang der Pipe
 
    // Auf Kindprozesse warten
    wait( &status );
    wait( &status );
  }
  exit(0);
}
Benannte Pipe
Vorgehensweise:
  1. Erster Prozess muss die Pipe mit der Systemfunktion >>mkfifo<< anlegen.
  2. Zweiter Prozess übernimmt die Rolle des Produzenten und schreibt seine Daten in die Pipe.
  3. Dritter Prozess übernimmt die Rolle des Konsumenten, welcher die in der Pipe liegenden Daten ausließt.
/**
* @desc Legt eine Pipe an.
* Danach kann Konsument und Produzent gestartet werden
*/
pipe_init ( )
{
  int status;
  status = mkfifo("./pipename", 0700); // Pipeline anlegen
 
 
  if( status == 0 ) // Bei Erfolg
  {
    printf("Pipe wurde angelegt");
    exit(0);
  }
 
 
  // Bei Misserfolg
  printf("Fehler beim anlegen der Pipe");
  exit(-1);
}
/**
* @desc Dient als Produzent.
* Schreibt einen Text in die Pipe
*/
pipe_produce ( )
{
  char *message;
  int fileDescriptor;
 
  message = "HalloWelt";
  fileDescriptor = open("./pipename", O_WRONLY); // Pipe öffnen
 
  if( fileDescriptor < 0 ) // Wenn Fehler
  {
    printf("Pipe konnte nicht geöffnet werden");
    exit(-1);
  }
 
  // Öffnen erfolgreich
  write(1, message, strlen(message) ); // in Pipe schreiben
 
  close(1);
  exit(0);
}
/**
* @desc Dient als Konsument.
* Ließt die Daten des Produzenten aus der Pipe
*/
pipe_consume ( )
{
  int fileDescriptor; // Dateideskriptor
  int count; // Anzahl der ausgelesenen Zeichen in read
  char buffer[255]; // Speicher anlegen
 
  fileDescriptor = open("./pipename", O_RDONLY); // Pipe öffnen
  if( fileDescriptor < 0 ) // Öffnen Fehlgeschlagen
  {
    printf("Pipe konnte nicht geöffnet werden");
    exit(-1);
  }
 
  // Öffnen erfolgreich
  if( count = read(0, buffer, 255) >= 1 ) // Wenn Daten vorhanden
  {
    for( i=0; i<count; i++ ) // gebe Daten aus
      printf("%c", buffer[i]); // %c = character ausgeben
  }
 
  unlink("./pipename"); // Löscht den Verzeichniseintrag
  exit(0);
}