超詳細的Linux守護進程介紹和工作原理說明

概述

1、守護進程的定義

守護進程也稱為精靈進程(Daemon),是運行在後臺的一種特殊進程。它獨立於控制終端並且週期性的執行某種發生的事件。守護進程是一種很有用的進程。Linux的大多數服務器就是用守護進程實現的。

Linux系統啟動時會啟動很多系統服務進程,這些系統服務進程沒有控制終端,不能直接和用戶交互。其他進程都是在用戶登錄或運行程序時創建,在運行結束或用戶註銷時終止,但系統服務進程(守護進程)不受用戶登錄註銷的影響,它們一直在運行著。這種進程有一個名稱叫守護進程(Daemon)。

下面們用ps axj命令查看系統中的進程。參數a 表示不僅列出當前用戶的進程,也列出所有其他用戶的進程; 參數x 表示不僅列出有控制終端的進程,也列出所有無控制終端的進程;參數j 表示列出與作業控制相關的信息。

超詳細的Linux守護進程介紹和工作原理說明

(1)凡是TPGID一欄寫著-1的都是沒有控制終端的進程,也就是守護進程;

(2)在COMMAND一列用[ ]括起來的名字表示內核線程,這些線程在內核裡創建,沒有用戶空間代碼,因此沒有程序文件名和命令行,通常採用以k開頭的名字,表示Kernel;

(3)init進程我們已經很熟悉了,udevd負責維護/dev目錄下的設備文件,acpid負責電源管理,syslogd負責維護/var/log下的日誌文件;

(4)可以看出,守護進程通常採用以d結尾的名字,表示Daemon。

2、守護進程的特點

(1)在Linux中,每個系統與用戶進行交流的界面成為終端,每一個從此終端開始運行的進程都會依附於這個終端,這個終端被稱為這些進程的控制終端;

(2)當控制終端被關閉的時候,相應的進程都會自動關閉。但是守護進程卻能突破這種限制,它脫離於終端並且在後臺運行,(脫離終端的目的是為了避免進程在運行的過程中的信息在任何終端中顯示並且進程也不會被任何終端所產生的終端信息所打斷),它從被執行的時候開始運轉,直到整個系統關閉才退出(當然可以認為是殺死相應的守護進程);

(3)如果想讓某個進程不因為用戶或中斷或其他變化而影響,那麼就必須把這個進程變成一個守護進程。

3、進程,進程組,會話,控制終端之間的關係

因為守護進程的創建需要改變這些環境參數,所以瞭解它們之間的關係很重要:

超詳細的Linux守護進程介紹和工作原理說明

上圖就描述了它們之間的聯繫:

進程組:它是由一個或多個進程組成,進程組號(GID)就是這些進程中的進程組長的PID。

會話:其實叫做會話期(session),它包括了期間所有的進程組,一般一個會話期開始於用戶login,一般login的是shell終端,所以shell終端又是此次會話期的首進程,會話一般結束於logout。對於非進程組長,它可以調用setsid()創建一個新的會話。

控制終端(tty):一般就是指shell終端,它在會話期中可有也可以沒有。


二、創建守護進程

創建守護進程最關鍵的一步是調用setsid函數創建一個新的Session Leader。

#include<unistd.h>
pid_t setid(void);
//該函數調用成功時返回新創建的Session的id(其實也就是當前進程的id),出錯返回-1。
/<unistd.h>

注意,調用這個函數之前,當前進程不允許是進程組的Leader,否則該函數返回-1。要保證當前進程不是進程組的Leader也很容易,只要先fork再調用setsid就行了。fork創建的子進程和父進程在同一個進程組中,進程組的Leader必然是該組的第一個進程,所以子進程不可能是該組的第一個進程,在子進程中調用setsid就不會有問題了。

成功調用該函數的結果是:

(1)創建一個新的Session,當前進程為Session Leader,當前進程的id就是Session的id;

(2)創建一個新的進程組,當前進程為進程組的Leader,當前進程的id就是進程組的id;

(3)如果當前進程原本有一個控制終端,則它失去這個終端,成為一個沒有控制終端的進程。(所謂失去控制終端指的是,原來的控制終端仍然是打開的,仍然可以讀寫,但只是一個普通的打開文件,而不是控制終端了)。


三、守護進程代碼

超詳細的Linux守護進程介紹和工作原理說明

1.調用umask將文件模式創建屏蔽字設置為0

umask(0);//umask必須清0,否則創建的新文件受系統默認權限的影響

文件權限掩碼是屏蔽掉文件權限中的對應位。

由於使用fork出來的子進程繼承了父進程的文件權限掩碼,這就給該子進程使用文件帶了很多的麻煩(比如父進程中的文件沒有執行文件的權限,然而在子進程中希望執行相應的文件這個時候就會出問題)。因此在子進程中要把文件的權限掩碼設置成為0(也就是說子進程有最大的權限),這樣做能增強該守護進程的靈活性。

2.調用fork函數,父進程退出(exit)

這樣的做的目的:

(1)保證子進程不是一個進程組的Leader;

(2)如果該守護進程作為一條簡單的shell命令啟動的,那麼父進程終止使得shell認為該命令已經執行完畢。

3.調用setsid創建一個新的會話

調用該函數的原因:

由於調用了fork()函數之後,子進程拷貝了父進程的會話期、進程組、控制終端的資源(雖然父進程退出了,這些資源都並沒有改變),因此需要調用setsid()函數來讓該子進程完全獨立出來,從而擺脫其他進程的控制。

4.忽略SIGCHLD信號

signal(SIGCHLD,SIG_IGN);

5.將當前工作目錄更改為根目錄

這樣做的目的是:

防止當前目錄有一個目錄被刪除,導致守護進程無效。(因為調用fork後的子進程繼承了父進程的當前工作目錄,由於在進程運行中,當前目錄所在的文件系統是不能被卸載的,這對以後使用會造成很多麻煩,因此,通常會讓"/"作為守護進程的當前目錄,當然也可以指定別的目錄來作為守護進程的當前工作目錄)

6.關閉不再需要的文件描述符

這樣做的目的:

同文件權限碼一樣,用fork出來的子進程會從父進程那裡繼承一些已經打開了的文件。這些被打開的文件可能永遠不會被守護進程讀寫,如果不關閉將會浪費系統的資源,造成進程所在的文件系統無法卸載或者引起一些不可預料的錯誤。


四、如何殺死守護進程

1.首先ps axj | grep 守護進程名字,找到相應的守護進程,然後使用kill -9 守護進程名殺掉;

2.利用ps -ef命令查找相應的守護進程,再用kill -9命令將其殺死;

3.創建shell腳本對進程的啟動、關閉、重啟進行自動管理。


篇幅有效,關於守護進程方面內容就介紹到這了,後面會分享更多Linux方面的乾貨,感興趣的朋友走一波關注哩~

超詳細的Linux守護進程介紹和工作原理說明


分享到:


相關文章: