it-swarm.com.de

Was ist der Grund für die Durchführung einer doppelten Verzweigung beim Erstellen eines Dämons?

Ich versuche einen Daemon in Python zu erstellen. Ich habe die folgende Frage gefunden, die einige gute Ressourcen enthält, die ich momentan verfolge, aber ich bin neugierig, warum eine Doppelgabel notwendig ist. Ich habe bei Google herumgekratzt und viele Ressourcen gefunden, die erklären, dass man notwendig ist, aber nicht warum.

Einige erwähnen, dass der Dämon daran gehindert wird, ein steuerndes Terminal zu erwerben. Wie würde es das ohne die zweite Gabel tun? Was sind die Auswirkungen?

145
Shabbyrobe

Betrachtet man den Code, auf den in der Frage verwiesen wird, lautet die Begründung:

# Fork a second child and exit immediately to prevent zombies.  This
# causes the second child process to be orphaned, making the init
# process responsible for its cleanup.  And, since the first child is
# a session leader without a controlling terminal, it's possible for
# it to acquire one by opening a terminal in the future (System V-
# based systems).  This second fork guarantees that the child is no
# longer a session leader, preventing the daemon from ever acquiring
# a controlling terminal.

Es ist also sicherzustellen, dass der Daemon auf init neu geordnet wird (nur für den Fall, dass der Prozess, der den Dämon startet, langlebig ist), und dass jede Chance, dass der Daemon ein kontrollierendes Steuerelement wiedererlangt, entfernt wird. Wenn also keiner dieser Fälle zutrifft, sollte eine Gabel ausreichend sein. " Unix Network Programming - Stevens " hat einen guten Abschnitt dazu.

101
Beano

Ich versuchte die Doppelgabel zu verstehen und bin hier auf diese Frage gestoßen. Nach langer Recherche habe ich das herausgefunden. Hoffentlich hilft es, die Dinge für jeden, der die gleiche Frage hat, besser zu erklären.

In Unix gehört jeder Prozess zu einer Gruppe, die wiederum zu einer Sitzung gehört. Hier ist die Hierarchie…

Sitzung (SID) → Prozessgruppe (PGID) → Prozess (PID)

Der erste Prozess in der Prozessgruppe wird zum Prozessgruppenleiter und der erste Prozess in der Sitzung wird zum Sitzungsleiter. Jeder Sitzung kann ein TTY zugeordnet sein. Nur ein Sitzungsleiter kann einen TTY steuern. Damit ein Prozess wirklich im Hintergrund abläuft (im Hintergrund ausgeführt), sollten wir sicherstellen, dass der Sitzungsleiter getötet wird, so dass keine Möglichkeit besteht, dass die Sitzung die Kontrolle über den TTY übernimmt. 

Ich habe Sander Marechals Python-Beispiel-Daemon-Programm von this site auf meinem Ubuntu ausgeführt. Hier sind die Ergebnisse mit meinen Kommentaren. 

1. `Parent`    = PID: 28084, PGID: 28084, SID: 28046
2. `Fork#1`    = PID: 28085, PGID: 28084, SID: 28046
3. `Decouple#1`= PID: 28085, PGID: 28085, SID: 28085
4. `Fork#2`    = PID: 28086, PGID: 28085, SID: 28085

Beachten Sie, dass der Prozess nach Decouple#1 der Sitzungsleiter ist, da er PID = SID ist. Es könnte immer noch die Kontrolle über einen TTY übernehmen.

Beachten Sie, dass Fork#2 nicht mehr der Sitzungsleiter PID != SID ist. Dieser Prozess kann niemals die Kontrolle über einen TTY übernehmen. Wirklich daemonisiert.

Ich persönlich finde die Zweideutigkeit der Terminologie verwirrend. Eine bessere Sprache könnte eine Gabel-Entkopplungs-Gabel sein.

Weitere Links von Interesse:

152

Genau genommen hat die Doppelgabel nichts damit zu tun, den Daemon als Kind von init neu zu erziehen. Alles, was erforderlich ist, um das Kind wieder zu erziehen, ist, dass das Elternteil beendet werden muss. Dies kann mit nur einer Gabel erfolgen. Wenn Sie eine Doppelgabelung selbst ausführen, wird der Dämonprozess nicht erneut an init übergeben. Das übergeordnete Element des Daemons muss beendet werden. Mit anderen Worten, das übergeordnete Element wird immer beendet, wenn ein richtiger Dämon gegabelt wird, sodass der Dämonprozess wieder init zugeordnet wird.

Warum also die Doppelgabel? POSIX.1-2008 Abschnitt 11.1.3, " The Controlling Terminal ", hat die Antwort (Hervorhebung hinzugefügt):

Das steuernde Terminal für eine Sitzung ist vom Sitzungsleiter zugewiesen implementierungsdefiniert. Wenn ein Sitzungsleiter kein steuerndes Terminal hat und eine Terminalgerätedatei öffnet, die noch nicht mit einer Sitzung verknüpft ist, ohne die Option O_NOCTTY zu verwenden (siehe open()), wird implementierungsdefiniert, ob das Terminal wird das steuernde Terminal des Sitzungsleiters. Wenn ein Prozess, der kein Sitzungsleiter ist, eine Terminaldatei öffnet oder die Option O_NOCTTY für open() verwendet wird, wird dieses Terminal nicht zum steuernden Terminal Terminal des aufrufenden Prozesses.

Dies sagt uns, dass, wenn ein Daemon-Prozess so etwas tut ...

int fd = open("/dev/console", O_RDWR);

... dann kann der Daemon-Prozess /dev/console als steuerndes Terminal annehmen, abhängig davon, ob der Daemon-Prozess ein Sitzungsleiter ist und abhängig von der Systemimplementierung. Das Programm kann garantieren , dass der obige Aufruf kein steuerndes Terminal erhält, wenn das Programm zuerst sicherstellt, dass es kein Sitzungsleiter ist.

Normalerweise wird beim Starten eines Daemons setsid aufgerufen (vom untergeordneten Prozess nach dem Aufruf von fork), um den Daemon von seinem steuernden Terminal zu trennen. Das Aufrufen von setsid bedeutet jedoch auch, dass der aufrufende Prozess der Sitzungsleiter der neuen Sitzung ist, wodurch die Möglichkeit offen bleibt, dass der Dämon ein steuerndes Terminal erneut abrufen kann. Die Double-Fork-Technik stellt sicher, dass der Daemon-Prozess nicht der Sitzungsleiter ist. Dadurch wird sichergestellt, dass ein Aufruf von open, wie im obigen Beispiel, nicht dazu führt, dass der Daemon-Prozess ein steuerndes Terminal erneut anfordert.

Die Doppelgabeltechnik ist etwas paranoid. Es ist möglicherweise nicht erforderlich, wenn Sie wissen , dass der Dämon niemals eine Endgerätedatei öffnet. Auf einigen Systemen ist dies möglicherweise auch dann nicht erforderlich, wenn der Dämon eine Endgerätedatei öffnet, da dieses Verhalten von der Implementierung abhängig ist. Nicht implementierungsspezifisch ist jedoch, dass nur ein Sitzungsleiter das steuernde Terminal zuweisen kann. Wenn ein Prozess kein Sitzungsleiter ist, kann er kein steuerndes Terminal zuweisen. Wenn Sie also paranoid sein und sicher sein möchten, dass der Dämonprozess unabhängig davon kein steuerndes Terminal versehentlich abrufen kann Für alle implementierungsspezifischen Besonderheiten ist die Doppelgabel-Technik unabdingbar.

104
Dan Moulding

Entnommen von Bad CTK :

"Bei einigen Unix-Varianten müssen Sie beim Start eine doppelte Verzweigung ausführen, um in den Dämonmodus zu wechseln. Dies liegt daran, dass es nicht garantiert ist, dass sich einzelne Gabelungen vom steuernden Terminal lösen."

11
Stefan Thyberg

Laut "Advanced Programming in der Unix-Umgebung" von Stephens und Rago ist die zweite Verzweigung eher eine Empfehlung und es wird sichergestellt, dass der Dämon auf System V-basierten Systemen kein steuerndes Terminal erhält. 

8
Paolo Tedesco

Ein Grund ist, dass der übergeordnete Prozess sofort wait_pid () für das untergeordnete Element abrufen und es dann vergessen kann. Wenn dann das Enkelkind stirbt, ist es ein Elternteil von init, und es wartet () darauf - und nimmt es aus dem Zombie-Zustand heraus. 

Das Ergebnis ist, dass der übergeordnete Prozess nicht über die verzweigten untergeordneten Elemente informiert werden muss und dass es auch möglich ist, lange laufende Prozesse von Bibliotheken usw. zu trennen.

3
KarlP

Der Aufruf von daemon () hat den übergeordneten Aufruf _exit (), wenn er erfolgreich ist. Die ursprüngliche Motivation war möglicherweise, dem Elternteil zusätzliche Arbeit zu ermöglichen, während das Kind die Daemonisierung durchführt.

Sie kann auch auf der falschen Annahme beruhen, dass es notwendig ist, um sicherzustellen, dass der Daemon keinen übergeordneten Prozess hat und für init neu geschrieben wird. Dies wird jedoch ohnehin passieren, wenn das übergeordnete Element in einem Fall mit nur einer Gabelung stirbt.

Ich nehme an, es läuft am Ende alles auf die Tradition hinaus - eine einzige Gabel reicht aus, solange das Elternteil in kurzer Zeit stirbt.

2
bdonlan

Eine anständige Diskussion darüber scheint bei http://www.developerweb.net/forum/showthread.php?t=3025 zu sein. _

Mlampkin zitiert von dort:

... man denke an den Aufruf von setsid () als "neuen" Weg, um Dinge zu tun (vom Terminal trennen) und den [zweiten] Fork () - Aufruf danach als Redundanz, um mit dem SVr4 fertig zu werden ...

2
Stobor

Es könnte einfacher sein, auf diese Weise zu verstehen:

  • Der erste Zweig und die Set-ID erstellen eine neue Sitzung (aber die Prozess-ID == Sitzungs-ID).
  • Die zweite Verzweigung stellt die Prozess-ID! = Sitzungs-ID sicher.
0
pandy.song