| Titel: | C Prozesse mit Pipe verbinden | |
| Beschreibung: | Wie man unter Linux eine Pipe zur Kommunikation zwischen zwei Prozessen benutzt. | |
| Kategorie: | Programmierung | |
| Unterkategorie | C/C++ | |
| Benötigtes Fachwissen: | Profi | |
| Artikel überarbeiten: | C Prozesse mit Pipe verbinden | |
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:
- Elternprozess muss die Funktion pipe() aufrufen, um eine Pipe zu erzeugen.
- Elternprozess erzeugt zwei Kindprozesse. Somit wird die >>File Descriptor Table<< mit allen Deskriptoren mit vererbt.
- Kindprozesse erzeugen über die Funktion dup2() einen neuen Eintrag in der >>File Descriptor Table<<
- Kindprozesse schließen mit der Funktion close() die Pipe.
- 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); }
Vorgehensweise:
- Erster Prozess muss die Pipe mit der Systemfunktion >>mkfifo<< anlegen.
- Zweiter Prozess übernimmt die Rolle des Produzenten und schreibt seine Daten in die Pipe.
- 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); }
FileDescriptor, open() und write()