programing tip

데몬을 만들 때 이중 포크를 수행하는 이유는 무엇입니까?

itbloger 2020. 6. 6. 08:44
반응형

데몬을 만들 때 이중 포크를 수행하는 이유는 무엇입니까?


파이썬에서 데몬을 만들려고합니다. 다음 질문을 찾았습니다.이 질문 에는 현재 팔로우하고있는 좋은 자료가 있지만 왜 이중 포크가 필요한지 궁금합니다. 나는 구글을 긁었고 하나는 필요하다고 선언하는 많은 리소스를 찾았지만 그 이유는 아닙니다.

어떤 사람들은 데몬이 제어 터미널을 얻는 것을 막는 것이라고 언급합니다. 두 번째 포크가 없으면 어떻게할까요? 영향은 무엇입니까?


질문에서 참조 된 코드를 보면 정당성은 다음과 같습니다.

# 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.

따라서 데몬이 init로 다시 보호되도록 (데몬을 시작하는 프로세스가 오래 지속되는 경우를 대비하여) 데몬이 제어 tty를 다시 획득 할 가능성을 제거합니다. 따라서 이러한 경우 중 어느 것도 해당되지 않으면 하나의 포크이면 충분합니다. " 유닉스 네트워크 프로그래밍-Stevens "에는 이것에 대한 좋은 섹션이 있습니다.


나는 이중 포크를 이해하려고 노력했고 여기 에서이 질문을 우연히 발견했습니다. 많은 연구 끝에 이것이 내가 알아 낸 것입니다. 다행스럽게도 같은 질문을 가진 사람에게는 더 잘 설명 할 수 있기를 바랍니다.

유닉스에서 모든 프로세스는 그룹에 속하고 세션에 속합니다. 계층 구조는 다음과 같습니다.

세션 (SID) → 프로세스 그룹 (PGID) → 프로세스 (PID)

프로세스 그룹의 첫 번째 프로세스는 프로세스 그룹 리더가되고 세션의 첫 번째 프로세스는 세션 리더가됩니다. 모든 세션에는 하나의 TTY가 연결될 수 있습니다. 세션 리더 만 TTY를 제어 할 수 있습니다. 프로세스가 실제로 백그라운드에서 실행 되려면 (백그라운드에서 실행 됨) 세션 리더가 종료되어 세션이 TTY를 제어 할 가능성이 없도록해야합니다.

우분투 의이 사이트 에서 Sander Marechal의 Python 예제 데몬 프로그램을 실행 했습니다 . 내 의견과 결과는 다음과 같습니다.

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

주 과정 후 세션 리더임을 Decouple#1이 때문에, PID = SID. 여전히 TTY를 제어 할 수 있습니다.

참고 Fork#2더 이상 세션 리더입니다 PID != SID. 이 프로세스는 TTY를 제어 할 수 없습니다. 정말 데몬입니다.

나는 개인적으로 혼란스러워하는 용어를 두 번이나 포크합니다. 더 좋은 관용구는 포크 분리 포크 일 수 있습니다.

추가 관심 링크 :


엄밀히 말하면, 이중 포크는 데몬의 부모로 부모의 상관이 없습니다 init. 자녀를 양부모로 만드는 데 필요한 모든 것은 부모가 종료해야한다는 것입니다. 이것은 하나의 포크로만 가능합니다. 또한 이중 포크 자체를 수행해도 데몬 프로세스의 부모가되지 않습니다 init. 데몬의 부모 종료 해야합니다 . 다시 말해, 데몬 프로세스가 부모로 변경되도록 적절한 데몬을 포크 할 때 부모는 항상 종료됩니다 init.

왜 더블 포크? POSIX.1-2008 섹션 11.1.3, " 제어 터미널 "에 답이 있습니다 (강조 추가).

세션에 대한 제어 단말기 는 구현 정의 방식으로 세션 리더의해 할당된다 . 세션 리더에 제어 터미널이없고 O_NOCTTY옵션 을 사용하지 않고 세션과 아직 연결되지 않은 터미널 장치 파일을 열면 (참조 open()) 터미널이 세션 리더의 제어 터미널이 될지 여부는 구현 정의됩니다. 인 프로세스가있는 경우 가 아닌 세션 리더가 터미널 파일을 열고, 또는 O_NOCTTY옵션이 사용됩니다 open(), 다음 터미널은 호출 프로세스의 제어 터미널이되지 아니한다 .

이것은 데몬 프로세스가 이와 같은 일을하면 ...

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

... 데몬 프로세스가 세션 리더인지 여부 및 시스템 구현에 따라 디먼 프로세스가 제어 터미널로 획득 할 수 있습니다/dev/console . 프로그램은 프로그램이 먼저 세션 리더가 아닌 것을 확인하면 위의 호출이 제어 터미널을 획득하지 않도록 보장 할 수 있습니다 .

일반적으로 데몬을 시작할 때을 setsid호출 한 후 자식 프로세스에서 호출 fork하여 데몬을 제어 터미널에서 분리합니다. 그러나 호출 setsid은 호출 프로세스가 새 세션의 세션 리더가되므로 데몬이 제어 터미널을 다시 획득 할 가능성을 열어 둡니다. 이중 포크 기술은 디먼 프로세스가 세션 리더가 아닌 것을 보장하며, open위의 예에서와 같이에 대한 호출 이 디먼 프로세스가 제어 터미널을 다시 획득하지 않도록합니다.

이중 포크 기술은 약간 편집증입니다. 당신이 경우는 필요하지 않을 수 있습니다 알고 데몬이 터미널 장치 파일을 열지 않을 것이다. 또한 일부 시스템에서는 데몬이 터미널 장치 파일을 열어도 동작이 구현 정의되어 있지 않아도 필요하지 않을 수 있습니다. 그러나 구현 정의되지 않은 한 가지는 세션 리더 만 제어 터미널을 할당 할 수 있다는 것입니다. 프로세스가 세션 리더가 아닌 경우 제어 터미널을 할당 할 수 없습니다. 따라서 편집증을 원하고 구현 정의에 상관없이 데몬 프로세스가 제어 터미널을 실수로 얻을 수없는 경우에는 이중 포크 기술이 필수적입니다.


나쁜 CTK 에서 가져온 :

"일부 버전의 Unix에서는 데몬 모드로 들어가기 위해 시작시 이중 포크를 수행해야합니다. 이는 단일 분기가 제어 터미널에서 분리되는 것을 보장하지 않기 때문입니다."


Stephens와 Rago의 "Unix Environment의 Advanced Programming"에 따르면, 두 번째 포크가 더 권장되며 데몬이 System V 기반 시스템에서 제어 터미널을 얻지 못하도록합니다.


한 가지 이유는 부모 프로세스가 자식을 즉시 wait_pid () 한 다음 잊어 버리기 때문입니다. 손자가 죽으면 부모가 초기화되고 기다립니다. 좀비 상태에서 빠져 나옵니다.

결과적으로 상위 프로세스는 분기 된 하위를 인식 할 필요가 없으며 라이브러리 등에서 오래 실행되는 프로세스를 분기 할 수 있습니다.


The daemon() call has the parent call _exit() if it succeeds. The original motivation may have been to allow the parent to do some extra work while the child is daemonizing.

It may also be based on a mistaken belief that it's necessary in order to ensure the daemon has no parent process and is reparented to init - but this will happen anyway once the parent dies in the single fork case.

So I suppose it all just boils down to tradition in the end - a single fork is sufficient as long as the parent dies in short order anyway.


A decent discussion of it appear to be at http://www.developerweb.net/forum/showthread.php?t=3025

Quoting mlampkin from there:

...think of the setsid( ) call as the "new" way to do thing (disassociate from the terminal) and the [second] fork( ) call after it as redundancy to deal with the SVr4...


It might be easier to understand in this way:

  • The first fork and setsid will create a new session (but the process ID == session ID).
  • The second fork makes sure the process ID != session ID.

참고URL : https://stackoverflow.com/questions/881388/what-is-the-reason-for-performing-a-double-fork-when-creating-a-daemon

반응형