UNIX pipes

UNIX pipes

Die Pipe (englisch für Rohr, Röhre) bezeichnet einen gepufferten uni- oder bidirektionalen Datenstrom zwischen zwei Prozessen nach dem „First In – First Out“-Prinzip. Das heißt vereinfacht, dass die Ausgabe eines Prozesses (ein Programm in Ausführung) als Eingabe für einen weiteren verwendet wird. Ein beliebtes Beispiel ist das Herausfiltern bestimmter Zeilen aus einer umfangreichen Datei, indem jede Zeile mit einem Muster verglichen wird:

cat haushaltsbuch | grep Lebensmittel

Hier wird der Inhalt der Datei „haushaltsbuch“ nicht direkt auf dem Bildschirm angezeigt, sondern als Eingabe für das Programm grep verwendet, das hier nur die Zeilen anzeigt, die das Wort „Lebensmittel“ enthalten. Diese könnte man durch Anfügen eines weiteren Pipe-Symbols (|) auch noch weiter verarbeiten, indem man beispielsweise die Summe bildet.

Inhaltsverzeichnis

Erzeugen einer Pipe

Nach Anforderung einer Pipe durch den Systemaufruf pipe() werden vom Betriebssystem zwei Zugriffskennungen (engl.: handles) zurückgeliefert, die zum Schreiben in die bzw. Lesen aus der Pipe benötigt werden. Auch Kindprozesse erben den Zugriff auf diese handles. Mit der Beendigung des letzten Prozesses, der Zugriff auf eine aktive Pipe hat, wird diese vom Betriebssystem beendet.

Pipe-Varianten

Es gibt anonyme und benannte Pipes.

Anonyme Pipes unterliegen drei erheblichen Einschränkungen:

  • Sie können nur in eine Richtung verwendet werden: ein Prozess schreibt, der andere liest.
  • Sie können nur für die Kommunikation zwischen eng verwandten Prozessen benutzt werden.
  • Die maximale Datenmenge, die eine Pipe enthalten kann, ist relativ klein.

Benannte Pipes (Named Pipes) können dagegen auch zur Kommunikation zwischen Prozessen eingesetzt werden, die nicht miteinander verwandt sind und sich darüber hinaus auf unterschiedlichen Rechnern innerhalb eines Netzwerkes befinden dürfen. Sie sind flexibler als anonyme Pipes und eignen sich für sogenannte Client-Server-Anwendungen (es lassen sich auch RPCs realisieren). Benannte Pipes ermöglichen die gleichzeitige Kommunikation in beide Richtungen, das heißt, Daten können im Vollduplexbetrieb zwischen den Prozessen ausgetauscht werden.

Jeder Prozess, der den Namen einer benannten Pipe kennt, kann über diesen Namen die Verbindung zur Pipe und damit zu anderen Prozessen herstellen.

Pipes in Betriebssystemen

Pipes sind in verschiedenen Betriebssystemen realisiert, die meisten bieten sowohl anonyme als auch benannte Pipes.

OS/2

OS/2 kennt anonyme und benannte Pipes. Benannte Pipes gehören zu den leistungsfähigsten IPC-Methoden, die OS/2 zu bieten hat. Wenn ein Server-Prozess eine benannte Pipe erzeugt, so kann er mehrere Instanzen dieser Pipe generieren, die alle unter demselben Namen angesprochen werden: Eine named pipe kann auch im Multiplexbetrieb arbeiten, so dass ein einzelner Server-Prozess mehrere Clients gleichzeitig bedienen kann.

Unix

Pipes sind unter Unix eines der mächtigsten Werkzeuge, um die sequentielle Abarbeitung von Befehlen auf einem bestimmten Datenbestand zu ermöglichen.

Bei einer anonymen Pipe ist die Kommunikation dabei auf zwei Prozesse gleichen Ursprungs beschränkt. Diese (Ursprungs-)Beziehung entsteht meistens durch Forks. In der Shell wird eine anonyme Pipe zum Startzeitpunkt der Programme durch Eingabe eines „|“-Zeichens erzeugt. Die Shell ist dann der (gemeinsame) Elternprozess beider Prozesse und erledigt die Forks automatisch.

Beispiel:

cat /var/log/messages | grep sshd

Hier wird die System-Logdatei nach dem Suchbegriff „sshd“ durchsucht.

Verlangt eine Anwendung die Angabe von Dateinamen für die Ein- oder Ausgabe, so kann man oft durch die Angabe eines Minuszeichens als Dateiname erreichen, dass auf die Standardausgabe geschrieben bzw. von der Standardeingabe gelesen wird. Auf diese Weise ist dann das Schreiben in bzw. das Lesen aus einer Pipe auch mit solchen Anwendungen realisierbar.

Beispiel:

tar c - /home/user/ogg/mycolouringbook | ssh -l user server "cd /var/ogg && tar xv -"

Hier wird der Inhalt eines Verzeichnisses mit tar zu einem Archiv zusammengepackt, über eine SSH-Verbindung zu einem anderen Rechner verschickt und dort entpackt.

Eine Named Pipe, auch FIFO (von first-in-first-out) genannt, ist eine Pipe, die von zwei Prozessen zur Laufzeit über einen Dateinamen zum Lesen oder Schreiben geöffnet werden kann. Bei einer Named Pipe müssen die Prozesse keinen gemeinsamen Ursprung haben, die Prozesse müssen lediglich zum Zugriff auf die Pipe autorisiert sein und den Namen der Pipe kennen.

Beispiel:

mkfifo einefifo
cat /var/log/messages > einefifo &
grep sshd < einefifo

FIFOs überdauern die sie verwendenden Prozesse, weil sie Bestandteil des Dateisystems sind. Allerdings kann eine FIFO keinen Inhalt haben, so lange sie von keinem Prozess geöffnet ist. Das bedeutet, dass der gepufferte Inhalt verloren geht, wenn ein schreibender Prozess sein Ende der Röhre schließt, ohne dass ein lesender Prozess das andere Ende geöffnet hat.

Standardimplementierung einer bidirektionalen Unix-Pipe:

Dieser Sourcecode bewirkt das gleiche wie die Shellanweisung who | sort

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
 
int main(void){
 
// pipe_verbindung[0] zum Lesen und pipe_verbindung[1] zum Schreiben
int pipe_verbindung[2];
 
//Initialisierung durch die Funktion Pipe
pipe(pipe_verbindung);
 
//Kindprozess erzeugen
if (fork()==0){
        // dup2 verbindet den Filedeskriptor der Pipe mit der Filedeskriptor der Standardausgabe
        dup2(pipe_verbindung[1],1);
 
        // der Leseausgang muss geschlossen werden, da dieser Prozess nichts liest
        close(pipe_verbindung[0]);
 
         // Kommando ausführen, Standardausgabe des Kommandos ist mit der Pipe verbunden
        execlp("who","who",NULL);
        } 
// dann zweiten Kindprozess erzeugen
else if (fork()==0){
        dup2(pipe_verbindung[0],0);
        close(pipe_verbindung[1]);
        execlp("sort","sort",NULL);        
        }
}

Der schreibende Prozess (Prozess1) hat zunächst auch lesenden Zugriff auf die Pipe (unidirektional). Deshalb muss er seinen Filedeskriptor(0) zum Lesen sperren. Genauso hat der lesende Prozess (Prozess2) zunächst schreibenden Zugriff auf die Pipe. Deshalb muss er seinen Filedeskriptor(1) zum Schreiben sperren. Werden die nicht benötigten Deskriptoren nicht gesperrt kommt es zu Komplikationen: Wenn zum Beispiel Prozess1 keine Daten mehr zu versenden hat terminiert er. Allerdings wird Prozess2 nicht terminieren, da noch ein Filedeskriptor(1) zum Schreiben (sein eigener) für weitere Eingaben auf die Pipe gesetzt ist. Er wartet bis in alle Ewigkeit.. aber es kommen keine Daten... Ein anderes denkbares Szenario ist, dass Prozess1 nicht terminieren kann, weil er Lesezugriff auf die Pipe hat und für immer und ewig auf Daten des Gegenspielers wartet, aber niemals welche ankommen werden, da er erstens schon längst terminiert ist und zweitens auch niemals welche gesendet hat.

Windows

Windows kennt anonyme und benannte Pipes. Benannte Pipes lassen sich über das Pipe-API analog zu den SMB-Freigaben als \\ServerName\pipe\PipeName ansprechen.

Implementierungen einer unnamed Pipe (anonyme Pipe) in C

Das Programm liest eine Benutzereingabe ein und nutzt dann eine Pipe, um die Daten einem Kindprozess mitzuteilen. Dieser wandelt alle Eingaben in Großbuchstaben (toupper) um und gibt diese aus.

#include <ctype.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
 
// Die maximale Laenge der Eingabe wird auf 2048 Bytes festgelegt.
#define MAX_ZEICHEN 2048
 
int main(void) {
	int fd[2], n, i;
	pid_t pid;
	char zeile[MAX_ZEICHEN];
 
	// Wir erstellen die Pipe. Tritt dabei ein Fehler auf, gibt die
	// Funktion -1 zurueck, so dass wir schon hier moegliche Fehler
	// abfangen und behandeln koennen.
	if (pipe(fd) < 0)
		fprintf(stderr, "Fehler beim Erstellen der pipe()");
 
	// Ein Kindprozess wird erstellt.
	if ((pid = fork()) > 0) {
		// Im Elternprozess
		close(fd[0]);
		fprintf(stdout, "Eltern : ");
		fgets(zeile, MAX_ZEICHEN, stdin);
		write(fd[1], zeile, strlen(zeile));
 
		if (waitpid(pid, NULL, 0) < 0)
			fprintf(stderr, "Fehler bei waitpid()");
	}
 
	// In den else-Zweig gelangt nur der Kindprozess
	else {
		// Im Kindprozess
		close(fd[1]);
		n = read(fd[0], zeile, MAX_ZEICHEN);
 
		for (i = 0; i < n; i++)
			zeile[i] = toupper(zeile[i]);
		fprintf(stderr, "Kind   : ");
 
		write(STDOUT_FILENO, zeile, n);
	}
	exit(0);
}

Weblinks


Wikimedia Foundation.

Игры ⚽ Поможем написать реферат

Schlagen Sie auch in anderen Wörterbüchern nach:

  • Unix — (officially trademarked as UNIX, sometimes also written as Unix with small caps) is a computer operating system originally developed in 1969 by a group of AT T employees at Bell Labs, including Ken Thompson, Dennis Ritchie, Douglas McIlroy, and… …   Wikipedia

  • Unix philosophy — The Unix philosophy is a set of cultural norms and philosophical approaches to developing software based on the experience of leading developers of the Unix operating system.McIlroy: A Quarter Century of UnixDoug McIlroy, the inventor of Unix… …   Wikipedia

  • Unix-Philosophie — Die Unix Philosophie ist eine Menge von Regeln und Herangehensweisen bei der Software Entwicklung, die auf den Erfahrungen der führenden Unix Programmierer basieren. Inhaltsverzeichnis 1 McIlroy: A Quarter Century of Unix 2 Pike: Notes on… …   Deutsch Wikipedia

  • Unix-Kommandos — Unix Systeme zeichnen sich durch eine Vielzahl von Kommandos aus, mit denen sich über eine Shell das Betriebssystem bedienen lässt. Die Syntax dieser Kommandos weicht unter den verschiedenen Systemen voneinander ab. Es existieren die beiden… …   Deutsch Wikipedia

  • UNIX-Kommandos — Unix Systeme zeichnen sich durch eine Vielzahl von Kommandos aus, mit denen sich über eine Shell das Betriebssystem bedienen lässt. Die Syntax dieser Kommandos weicht unter den verschiedenen Systemen voneinander ab. Es existieren die beiden… …   Deutsch Wikipedia

  • Unix-Befehle — Unix Systeme zeichnen sich durch eine Vielzahl von Kommandos aus, mit denen sich über eine Shell das Betriebssystem bedienen lässt. Die Syntax dieser Kommandos weicht unter den verschiedenen Systemen voneinander ab. Es existieren die beiden… …   Deutsch Wikipedia

  • Unix-Kommando — Unix Systeme zeichnen sich durch eine Vielzahl von Kommandos aus, mit denen sich über eine Shell das Betriebssystem bedienen lässt. Die Syntax dieser Kommandos weicht unter den verschiedenen Systemen voneinander ab. Es existieren die beiden… …   Deutsch Wikipedia

  • Unix Kommandos — Unix Systeme zeichnen sich durch eine Vielzahl von Kommandos aus, mit denen sich über eine Shell das Betriebssystem bedienen lässt. Die Syntax dieser Kommandos weicht unter den verschiedenen Systemen voneinander ab. Es existieren die beiden… …   Deutsch Wikipedia

  • UNIX — Ken Thompson und Dennis Ritchie Basisdaten Entwickler …   Deutsch Wikipedia

  • Unix — Kommandozeile (Unix Prompt) Basisdaten Entwickler Ken Thompso …   Deutsch Wikipedia

Share the article and excerpts

Direct link
Do a right-click on the link above
and select “Copy Link”