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

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

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



답변

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

좀비를 방지하기 위해 두 번째 아이를 포크하고 즉시 나가십시오. 이로 인해 두 번째 하위 프로세스가 분리되어 초기화 프로세스가 정리를 담당하게됩니다. 그리고 첫 번째 자식은 제어 터미널이없는 세션 리더이므로 나중에 터미널을 열어서이를 획득 할 수 있습니다 (System V 기반 시스템). 이 두 번째 포크는 자식이 더 이상 세션 리더가 아니 어서 데몬이 제어 터미널을 획득하지 못하게합니다.

따라서 데몬이 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 () 한 다음 잊어 버리기 때문입니다. 손자가 죽으면 부모가 초기화되고 기다립니다. 좀비 상태에서 빠져 나옵니다.

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


답변

daemon () 호출은 성공하면 상위 호출 _exit ()를 갖습니다. 원래 동기는 아이가 데몬을하는 동안 부모가 추가 작업을 수행하도록하는 것일 수 있습니다.

또한 데몬에 부모 프로세스가없고 init로 reparent하기 위해 필요하다는 잘못된 생각에 기초 할 수도 있습니다. 그러나 이것은 부모가 단일 포크 케이스에서 죽으면 어쨌든 일어날 것입니다.

그래서 나는 결국 모든 것이 전통으로 끝났다고 가정합니다. 어쨌든 부모가 짧은 순서로 죽는 한 싱글 포크이면 충분합니다.