摘要:本文主要介紹了Linux的守護進程的概念,重點分析了守護進程的特性及如何創建守護進程,并給出了具體的實現實例。
關鍵詞:守護進程 特性 創建守護進程
Linux系統啟動時會啟動很多系統服務進程,這些系統服務進程沒有控制終端,不能直接和用戶交互。其它進程都是在用戶登錄或運行程序時創建,在運行結束或用戶注銷時終止,但系統服務進程不受用戶登錄注銷的影響,它們一直在運行著,這種進程就是守護進程(daemon)。例如著名的apache、telnet、ftp等服務程序都是守護進程。除了服務進程外,守護進程還可以配合shell編程,設計出適合用戶自己的新功能,更好地維護系統,大大提高工作效率。比如,作業規劃進程crond。下面來介紹一下守護進程的特性及如何創建守護進程。
1 守護進程的特性
1.1 所有的守護進程都是以超級用戶啟動的(UID為0),所以編寫守護進程時要格外小心,編寫不好的守護進程很可能對系統造成威脅。
1.2 沒有一個守護進程具有控制終端,其終端名設置為問號(?),在后臺運行。
1.3 守護進程不存在父進程,雙親的進程都為1,即init進程。
1.4 所有用戶層守護進程都是進程組的組長進程以及會話的首進程,而且是這些進程組和會話中的唯一進程。
具有以上特征的進程就是守護進程,編寫守護進程的關鍵實際上就是要滿足守護進程的特性。
2 守護進程的編寫步驟
2.1 讓init進程成為新產生進程的父進程 程序運行后首先調用for函數創建子進程,并讓父進程退出。這樣,產生的子進程將變成孤兒進程,并被inti進程接管,同時,所產生的新進程將變為在后臺運行。
2.2 調用setsid函數 通過調用setsid函數,使得新創建的進程脫離控制終端,同時創建新的進程組,并成為該進程組的首進程。這個步驟是創建守護最重要的一步,為了更好地理解這一步驟,下面介紹一下進程組、會話的基本概念。
在Linux系統中,每個進程都屬于各自的進程組。進程組是一個或多個進程的集合。每個進程組都有類似于進程號的標識,稱為進程組ID。進程組ID是由首進程的進程號決定的,每個進程組都存在一個首進程。
會話是一個或多個進程組的集合。與進程組類似,每個會話都存在一個首進程。
會話和進程組是Linux內核管理多用戶情況下用戶進程的方法。每個進程都屬于一個進程組,而進程組又屬于某個會話。當用戶從終端登錄系統,系統會創建一個新的會話。在該終端上啟動的進程都會被系統劃歸到會話的進程組中。
會話中的進程是通過該會話中的首進程與終端相連的。該終端即是會話的控制終端。一個會話只能有一個控制終端。如果會話存在一個控制終端,則它必然擁有一個前臺進程組。屬于該組的進程可以從控制終端獲得輸入,而其他的進程組都為后臺進程組。
由于守護進程沒有控制終端,使用fork函數創建的子進程繼承了父進程的控制終端、會話和進程組,因此,必須創建新的會話,以脫離父進程的影響。setsid函數就是用于創建新會話的。
setsid函數創建新會話,并使得調用setsid函數的進程成為新會話的首進程。調用setsid函數的進程是新創建會話中的惟一的進程組,進程組ID為調用進程的進程號,同時要求調用進程不為一個進程的首進程。由于在第一步中調用fork的父進程退出,使得子進程不可能是進程組的首進程。該會話的首進程沒有控制終端與其相連。至此,滿足了守護進程沒有控制終端的要求。
2.3 改變當前目錄為根目錄 使用fork函數產生的子進程將繼承父進程的工作目錄,當進程沒有結束時,其工作目錄所在的文件系統不能卸下。一般需要將工作目錄改變到根目錄。更改工作目錄使用的函數是chdir。
2.4 重設文件權限掩碼 文件權限掩碼是用來屏蔽文件權限中的對應位的。由于使用fork函數新建的子進程繼承了父進程的文件權限掩碼,這會給子進程使用文件帶來了很多麻煩。因此,把文件權限掩碼設置為0,可以大大增強該守護進程的靈活性。設置文件權限掩碼的函數是umask。
2.5 關閉文件描述符 進程從創建它的父進程那里繼承了打開的文件描述符。如不關閉,將會浪費系統資源,造成進程所在的文件系統無法卸下以及引起無法預料的錯誤。關閉它們的方法是:
for(i=0;i close(i); 3 守護進程實例 下面給出一個創建守護進程的實例,該守護進程實例包括兩部分:主程序main.c和初始化程序init.c。主程序每隔10秒向目錄/tmp中的日志daemon.log報告運行狀態。初始化程序中的init_daemon函數負責生成守護進程。 3.1 初始化程序init.c #include < unistd.h > #include < signal.h > #include < sys/param.h > #include < sys/types.h > #include < sys/stat.h > #define MAXFILE 65535 void init_daemon(void) {int pid; int i; if(pid=fork()) exit(0);//創建子進程,結束父進程 else if(pid< 0) exit(1);/創建子進程失敗 setsid();//創建新會話,并擔任該會話組的組長 chdir(\"/tmp\");//改變工作目錄到/tmp下 for(i=0;i< MAXFILE;i++)//關閉打開的文件描述符 close(i); umask(0);//重設文件權限掩碼 } 3.2 主程序main.c #include < stdio.h > #include < time.h > void init_daemon(void);//守護進程初始化函數 main() {FILE *fp; time_t t; init_daemon();//初始化為daemon while(1)//每隔10秒向daemon.log報告運行狀態 {sleep(10);//睡眠10秒 if((fp=fopen(\"daemon.log\",\"a\")) >=0) { t=time(0); fprintf(fp,\" 守護進程還在運行,時間是:%s\\",asctime(localtime(t)) ); fclose(fp); } } } 程序運行結果如圖1: 運行該程序,它變成了一個守護進程,不再和當前終端關聯。用ps命令看不到,必須帶參數x才能看到。另外可以看到,用戶關閉終端窗口或注銷也不會影響守護進程的運行。 4 結束語 守護進程廣泛應用于Linux/Unix環境下的系統管理、網絡通信以及嵌入式應用等領域。本文分析了Linux守護進程的特性及如何創建守護進程,結合應用心得給出了程序實例,使其具有一定的實用性。 參考文獻: [1]張海.一種Linux操作系統守護進程的編程實現方法[J].廣東水利電力職業技術學院學報,2006[2]:57-59. [2]李玉波,朱自強,郭軍.《Linux C編程》.清華大學出版社,2005. [3]杜華.《Linux編程技術詳解》.人民郵電出版社,2007. [4]曹江華.《Linux最佳實踐工具》.電子工業出版社,2009. 作者簡介:王艷麗(1978-),女,講師,碩士研究生。研究方向:軟件工程,操作系統。