【Linux系统编程】特殊进程之守护进程
00. 目錄
文章目錄
- 00. 目錄
- 01. 守護進程概述
- 02. 守護進程查看方法
- 03. 編寫守護進程的步驟
- 04. 守護進程代碼
- 05. 附錄
01. 守護進程概述
守護進程(Daemon Process),也就是通常說的 Daemon 進程(精靈進程),是 Linux 中的后臺服務進程。它是一個生存期較長的進程,通常獨立于控制終端并且周期性地執行某種任務或等待處理某些發生的事件。
守護進程是個特殊的孤兒進程,這種進程脫離終端,為什么要脫離終端呢?之所以脫離于終端是為了避免進程被任何終端所產生的信息所打斷,其在執行過程中的信息也不在任何終端上顯示。由于在 Linux 中,每一個系統與用戶進行交流的界面稱為終端,每一個從此終端開始運行的進程都會依附于這個終端,這個終端就稱為這些進程的控制終端,當控制終端被關閉時,相應的進程都會自動關閉。
Linux 的大多數服務器就是用守護進程實現的。比如,Internet 服務器 inetd,Web 服務器 httpd 等。
02. 守護進程查看方法
在終端輸入ps axj
- a 表示不僅列當前用戶的進程,也列出所有其他用戶的進程
- x 表示不僅列有控制終端的進程,也列出所有無控制終端的進程
- j 表示列出與作業控制相關的信息
從上面的結果可以看出守護進程的一些特點:
- 守護進程基本上都是以超級用戶啟動( UID 為 0 )
- 沒有控制終端( TTY 為 ?)
- 終端進程組 ID 為 -1 ( TPGID 表示終端進程組 ID)
一般情況下,守護進程可以通過以下方式啟動:
- 在系統啟動時由啟動腳本啟動,這些啟動腳本通常放在 /etc/rc.d 目錄下;
- 利用 inetd 超級服務器啟動,如 telnet 等;
- 由 cron 定時啟動以及在終端用 nohup 啟動的進程也是守護進程。
03. 編寫守護進程的步驟
3.1 屏蔽一些控制終端操作的信號
這是為了防止守護進行在沒有運行起來前,控制終端受到干擾退出或掛起。
signal(SIGTTOU,SIG_IGN); signal(SIGTTIN,SIG_IGN); signal(SIGTSTP,SIG_IGN); signal(SIGHUP ,SIG_IGN);3.2 父進程退出
守護進程不可以是組長進程。方法是在進程中調用 fork() 使父進程終止, 讓守護進行在子進程中后臺執行。形式上脫離了控制終端。
if( pid = fork() ){ // 父進程exit(0); //結束父進程,子進程繼續 }3.3 創建會話,完全脫離控制終端
有必要先介紹一下 Linux 中的進程與控制終端,登錄會話和進程組之間的關系:進程屬于一個進程組,進程組號(GID)就是進程組長的進程號(PID)。登錄會話可以包含多個進程組。這些進程組共享一個控制終端。這個控制終端通常是創建進程的 shell 登錄終端。 控制終端、登錄會話和進程組通常是從父進程繼承下來的。我們的目的就是要擺脫它們 ,使之不受它們的影響。因此需要調用 setsid() 使子進程成為新的會話組長,示例代碼如下:
setsid();setsid() 調用成功后,進程成為新的會話組長和新的進程組長,并與原來的登錄會話和進程組脫離。由于會話過程對控制終端的獨占性,進程同時與控制終端脫離。
3.4 關閉不需要文件描述符
進程從創建它的父進程那里繼承了打開的文件描述符。如不關閉,將會浪費系統資源,造成進程所在的文件系統無法卸下以及引起無法預料的錯誤。按如下方法關閉它們:
3.5 改變當前工作目錄
進程活動時,其工作目錄所在的文件系統不能卸下。一般需要將工作目錄改變到根目錄。對于需要轉儲核心,寫運行日志的進程將工作目錄改變到特定目錄如 /tmp。示例代碼如下:
chdir("/");3.6 設置權限掩碼
進程從創建它的父進程那里繼承了文件創建掩碼。它可能修改守護進程所創建的文件的存取權限。為防止這一點,將文件創建掩碼清除:
umask(0);3.7 處理 SIGCHLD 信號
但對于某些進程,特別是服務器進程往往在請求到來時生成子進程處理請求。如果父進程不等待子進程結束,子進程將成為僵尸進程(zombie)從而占用系統資源(關于僵尸進程的更多詳情,請看《特殊進程之僵尸進程》)。如果父進程等待子進程結束,將增加父進程的負擔,影響服務器進程的并發性能。在 Linux 下可以簡單地將 SIGCHLD 信號的操作設為 SIG_IGN 。
signal(SIGCHLD, SIG_IGN);這樣,內核在子進程結束時不會產生僵尸進程。
04. 守護進程代碼
守護進程參考代碼:
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/types.h> #include <sys/stat.h> #include <unistd.h>int main(void) {int i = 0;pid_t pid = -1;//a. 設置掩碼umask(0); //b. 創建子進程 父進程退出pid = fork();if (-1 == pid){perror("fork"); goto err0;}else if (0 != pid){//父進程exit(0); }//子進程//c. 創建一個新的會話setsid();//d. 更改當前工作目錄chdir("/"); //e. 關系不需要的描述符close(0); close(1);close(2);//做事情while(1){system("echo hello world >> /tmp/a"); sleep(1); }return 0; err0:return 1; }測試結果:
05. 附錄
5.1 參考博客:【Linux系統編程】特殊進程之守護進程
總結
以上是生活随笔為你收集整理的【Linux系统编程】特殊进程之守护进程的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【Linux系统编程】特殊进程之孤儿进程
- 下一篇: 【Linux系统编程】进程替换:exec