wake-up-neo.com

dup2 / dup - warum sollte ich einen Dateideskriptor duplizieren müssen?

Ich versuche die Verwendung von dup2 Und dup zu verstehen.

Von der Manpage:

DESCRIPTION

dup and dup2 create a copy of the file descriptor oldfd.
After successful return of dup or dup2, the old and new descriptors may
be used interchangeably. They share locks, file position pointers and
flags; for example, if the file position is modified by using lseek on
one of the descriptors, the position is also changed for the other.

The two descriptors do not share the close-on-exec flag, however.

dup uses the lowest-numbered unused descriptor for the new descriptor.

dup2 makes newfd be the copy of oldfd, closing newfd first if necessary.  

RETURN VALUE

dup and dup2 return the new descriptor, or -1 if an error occurred 
(in which case, errno is set appropriately).  

Warum sollte ich diesen Systemaufruf benötigen? Was nützt es, den Dateideskriptor zu duplizieren?

Wenn ich den Dateideskriptor habe, warum sollte ich eine Kopie davon erstellen?

Ich würde mich freuen, wenn Sie mir erklären und ein Beispiel geben könnten, in dem dup2/dup benötigt wird.

Vielen Dank

74
JAN

Der Systemaufruf dup dupliziert einen vorhandenen Dateideskriptor und gibt einen neuen zurück, der auf dasselbe zugrunde liegende E/A-Objekt verweist.

Mit Dup können Shells Befehle wie folgt implementieren:

ls existing-file non-existing-file > tmp1  2>&1

2> & 1 weist die Shell an, dem Befehl einen Dateideskriptor 2 zuzuweisen, der ein Duplikat von Deskriptor 1 ist.
Nun die Fehlermeldung zum Aufrufen von ls on nicht existierende Datei und die korrekte Ausgabe von ls on existierende Datei) datei erscheint in tmp1 datei.

Der folgende Beispielcode führt das Programm wc mit der Standardeingabe aus, die mit dem Leseende einer Pipe verbunden ist.

int p[2];
char *argv[2];
argv[0] = "wc";
argv[1] = 0;
pipe(p);
if(fork() == 0) {
    close(STDIN); //CHILD CLOSING stdin
    dup(p[STDIN]); // copies the fd of read end of pipe into its fd i.e 0 (STDIN)
    close(p[STDIN]);
    close(p[STDOUT]);
    exec("/bin/wc", argv);
} else {
    write(p[STDOUT], "hello world\n", 12);
    close(p[STDIN]);
    close(p[STDOUT]);
}

Das untergeordnete Element überträgt das gelesene Ende auf den Dateideskriptor 0, schließt die Skriptdatei in p und führt wc aus. Wenn wc von seiner Standardeingabe liest, liest es von der Pipe.
So werden Pipes mit Hilfe von dup implementiert. Nun, eine Verwendung von dup verwendet Pipe, um etwas anderes zu erstellen. Das ist das Schöne an Systemaufrufen. Sie erstellen eine Sache nach der anderen mit den bereits vorhandenen Werkzeugen, diesen Werkzeuge wurden mit etwas anderem gebaut. Am Ende sind Systemaufrufe die grundlegendsten Werkzeuge, die man im Kernel bekommt

Prost :)

39
Deepthought

Ein weiterer Grund für das Duplizieren eines Dateideskriptors ist dessen Verwendung mit fdopen. fclose schließt den Dateideskriptor, der an fdopen übergeben wurde. Wenn Sie also nicht möchten, dass der ursprüngliche Dateideskriptor geschlossen wird, müssen Sie ihn zuerst mit dup duplizieren.

16
R..

Einige Punkte im Zusammenhang mit dup/dup2 können Sie bitte notieren

dup/dup2 - Technisch gesehen besteht der Zweck darin, einen Dateitabelleneintrag innerhalb eines einzelnen Prozesses durch verschiedene Handles gemeinsam zu nutzen. (Wenn wir forken, wird der Deskriptor im untergeordneten Prozess standardmäßig dupliziert und der Eintrag in der Dateitabelle wird ebenfalls gemeinsam genutzt.).

Das heißt, wir können mehr als einen Dateideskriptor mit möglicherweise unterschiedlichen Attributen für einen einzelnen Eintrag in einer geöffneten Dateitabelle mit der Funktion dup/dup2 haben.

(Allerdings scheint derzeit nur das FD_CLOEXEC-Flag das einzige Attribut für einen Dateideskriptor zu sein).

http://www.gnu.org/software/libc/manual/html_node/Descriptor-Flags.html

dup(fd) is equivalent to fcntl(fd, F_DUPFD, 0);

dup2(fildes, fildes2); is equivalent to 

   close(fildes2);
   fcntl(fildes, F_DUPFD, fildes2);

Unterschiede sind (für den letzten) - Abgesehen von einigen Fehlern zwischen dup2 und fcntl close, gefolgt von fcntl, können die Race-Bedingungen erhöht werden, da zwei Funktionsaufrufe beteiligt sind.

Details können unter http://pubs.opengroup.org/onlinepubs/009695399/functions/dup.html überprüft werden

Ein Anwendungsbeispiel -

Ein interessantes Beispiel für die Implementierung der Jobsteuerung in einer Shell, in der die Verwendung von dup/dup2 angezeigt wird

http://www.gnu.org/software/libc/manual/html_node/Launching-Jobs.html#Launching-Jobs

dup wird verwendet, um die Ausgabe eines Prozesses umzuleiten.

Wenn Sie beispielsweise die Ausgabe eines Prozesses speichern möchten, duplizieren Sie die Ausgabe (fd = 1), leiten die duplizierte fd in eine Datei um, verzweigen den Prozess und führen ihn aus, und wenn der Prozess abgeschlossen ist, leiten Sie die Ausgabe erneut um fd zur ausgabe gespeichert.

4
alinsoar