2012-01-08 72 views
21

當我試着寫用C在linux下一個守護進程,我被告知我應該後代碼塊中添加以下代碼:編寫Linux守護進程時,爲什麼必須從tty中分離出來?

/* Preparations */ 
... 

/* Fork a new process */ 
pid_t cpid = fork(); 
if (cpid == -1){perror("fork");exit(1);} 
if (cpid > 0){exit(0);} 

/* WHY detach from tty ? */ 
int fd = open("/dev/tty", O_RDWR); 
ioctl(fd, TIOCNOTTY, NULL); 

/* Why set PGID as current PID ? */ 
setpgid(getpid(), 0); 

我的問題是: 有一個必須做以上操作?

+0

我想部分原因是守護進程不希望寫輸出或讀輸入。如果你要開始,例如在SSH會話中使用HTTP服務器,您不會期望會話中的隨後的警告輸出。 – 2012-01-08 12:48:11

+1

@JohnChadwick你說的確實是你在轉換成守護進程時想要做的事情之一,但是通過關閉stdin,stdout和stderr來實現這一點。您從終端上分離以避免某些信號(請參閱下面的答案)。 – 2012-01-08 13:01:22

+1

你可以「不接受」我的回答並接受@ AdamZalcman的代替嗎?他比我做得好得多。他對setsid()完全正確,你應該使用它。 – fge 2012-01-08 13:05:55

回答

34

必須從終端撇清你的守護進程,以避免被涉及到終端的操作中發送的信號(如SIGHUP當終端會話結束以及潛在SIGTTIN和SIGTTOU)。

注意然而,從使用TIOCNOTTY ioctl終端解除關聯的方式在很大程度上是過時的。您應該改用setsid()

守護進程離開其原始進程組的原因是不接收發送到該組的信號。請注意,setsid()也會將您的流程置於其自己的流程組中。

+2

+1 setsid()' – fge 2012-01-08 13:02:41

+0

+1對於一個非常好的和完整的答案,尤其是「我們爲什麼要這麼做?」部分。 – 2012-01-08 13:10:20

+0

+1。警告:即使在setsid(2)之後,如果不小心(fork()或O_NOCTTY),也可能獲取控制終端。 – pilcrow 2012-01-08 16:34:00

10

另一個答案是清楚的,技術上是正確的(所以我相應地upvoted)。

另一個答案是:「不,不要說daemonizes自己寫的代碼。」

取而代之的是使用一個過程監督框架(如daemontoolsrunitlaunchd)來爲您處理此問題。

傳統的UNIX服務器是自我守護進程,因此在許多方面都有問題:當前工作目錄,進程組和會話獨立性,信號掩碼和處置,文件系統根目錄,權限,umask,打開文件描述符等。

然而,大多數或所有這些過程屬性都跨越exec()繼承,也就是說一個服務器進程通常可以「生」與所需的進程組,工作目錄,根等,這裏有一點需要做好自己的一切,儘管你通常仍然需要自己管理特權操作和權限撤銷。 (事實上​​,我認爲在編寫自我後臺程序時存在長期風險,並且複製粘貼並且倉促地移植和擴展了鍋爐板「後臺」程序,程序員花費時間在輔助代碼上而不是在程序的主要目的。)

+0

很好的回答!守護進程應該是調用者的選擇,而不是應用程序本身強制的選擇。而對於調用者來說,有很多現有的工具,不需要在應用程序中重新創建它。 – 2017-02-16 10:50:16