轉載出處:
https://blog.csdn.net/lianghe_work/article/details/47659889什麼是守護進程?
守護進程(Daemon Process),也就是通常說的 Daemon 進程(精靈進程),是 Linux 中的後臺服務進程。它是一個生存期較長的進程,通常獨立於控制終端並且週期性地執行某種任務或等待處理某些發生的事件。
守護進程是個特殊的孤兒進程,這種進程脫離終端,爲什麼要脫離終端呢?之所以脫離於終端是爲了避免進程被任何終端所產生的信息所打斷,其在執行過程中的信息也不在任何終端上顯示。由於在 Linux 中,每一個系統與用戶進行交流的界面稱爲終端,每一個從此終端開始運行的進程都會依附於這個終端,這個終端就稱爲這些進程的控制終端,當控制終端被關閉時,相應的進程都會自動關閉。
Linux 的大多數服務器就是用守護進程實現的。比如,Internet 服務器 inetd,Web 服務器 httpd 等。
如何查看守護進程
在終端敲:ps axj
- a 表示不僅列當前用戶的進程,也列出所有其他用戶的進程
- x 表示不僅列有控制終端的進程,也列出所有無控制終端的進程
- j 表示列出與作業控制相關的信息
從上圖可以看出守護進行的一些特點:
- 守護進程基本上都是以超級用戶啓動( UID 爲 0 )
- 沒有控制終端( TTY 爲 ?)
- 終端進程組 ID 爲 -1 ( TPGID 表示終端進程組 ID)
一般情況下,守護進程可以通過以下方式啓動:
- 在系統啓動時由啓動腳本啓動,這些啓動腳本通常放在 /etc/rc.d 目錄下;
- 利用 inetd 超級服務器啓動,如 telnet 等;
- 由 cron 定時啓動以及在終端用 nohup 啓動的進程也是守護進程。
如何編寫守護進程?
- signal(SIGTTOU,SIG_IGN);
- signal(SIGTTIN,SIG_IGN);
- signal(SIGTSTP,SIG_IGN);
- signal(SIGHUP ,SIG_IGN);
- if( pid = fork() ){ // 父進程
- exit(0); //結束父進程,子進程繼續
- }
- setsid();
setsid() 調用成功後,進程成爲新的會話組長和新的進程組長,並與原來的登錄會話和進程組脫離。由於會話過程對控制終端的獨佔性,進程同時與控制終端脫離。
- if( pid=fork() ){ // 父進程
- exit(0); // 結束第一子進程,第二子進程繼續(第二子進程不再是會話組長)
- }
- // NOFILE 爲 <sys/param.h> 的宏定義
- // NOFILE 爲文件描述符最大個數,不同系統有不同限制
- for(i=0; i< NOFILE; ++i){// 關閉打開的文件描述符
- close(i);
- }
6)改變當前工作目錄
- chdir("/");
- umask(0);
8)處理 SIGCHLD 信號
- signal(SIGCHLD, SIG_IGN);
這樣,內核在子進程結束時不會產生殭屍進程。
- #include <unistd.h>
- #include <signal.h>
- #include <fcntl.h>
- #include <sys/syslog.h>
- #include <sys/param.h>
- #include <sys/types.h>
- #include <sys/stat.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <time.h>
- int init_daemon(void)
- {
- int pid;
- int i;
- // 1)屏蔽一些控制終端操作的信號
- signal(SIGTTOU,SIG_IGN);
- signal(SIGTTIN,SIG_IGN);
- signal(SIGTSTP,SIG_IGN);
- signal(SIGHUP ,SIG_IGN);
- // 2)在後臺運行
- if( pid=fork() ){ // 父進程
- exit(0); //結束父進程,子進程繼續
- }else if(pid< 0){ // 出錯
- perror("fork");
- exit(EXIT_FAILURE);
- }
- // 3)脫離控制終端、登錄會話和進程組
- setsid();
- // 4)禁止進程重新打開控制終端
- if( pid=fork() ){ // 父進程
- exit(0); // 結束第一子進程,第二子進程繼續(第二子進程不再是會話組長)
- }else if(pid< 0){ // 出錯
- perror("fork");
- exit(EXIT_FAILURE);
- }
- // 5)關閉打開的文件描述符
- // NOFILE 爲 <sys/param.h> 的宏定義
- // NOFILE 爲文件描述符最大個數,不同系統有不同限制
- for(i=0; i< NOFILE; ++i){
- close(i);
- }
- // 6)改變當前工作目錄
- chdir("/tmp");
- // 7)重設文件創建掩模
- umask(0);
- // 8)處理 SIGCHLD 信號
- signal(SIGCHLD,SIG_IGN);
- return 0;
- }
- int main(int argc, char *argv[])
- {
- init_daemon();
- while(1);
- return 0;
- }
運行結果如下: