守護進程
守護進程,也就是通常說的Daemon進程,是Linux中的后台服務進程。它是一個生存期較長的進程,通常獨立於控制終端並且周期性地執行某種任務或等待處理某些發生的事件。守護進程常常在系統引導裝入時啟動,在系統關閉時終止。Linux系統有很多守護進程,大多數服務都是通過守護進程實現的。
守護進程的特點
由於在Linux中,每一個系統與用戶進行交流的界面稱為終端,每一個從此終端開始運行的進程都會依附於這個終端,這個終端就稱為這些進程的控制終端,當控制終端被關閉時,相應的進程都會自動關閉。但是守護進程卻能夠突破這種限制,它從被執行開始運轉,直到整個系統關閉時才退出。如果想讓某個進程不因為用戶或終端或其他地變化而受到影響,那么就必須把這個進程變成一個守護進程。
守護進程的概念類似於我們手機后台運行的程序,我們看不見它,它卻一直在運行。在Windows系統下也有很多服務,都是所謂的守護進程。
服務器與守護進程
Linux的大多數服務器就是用守護進程實現的。比如,Internet服務器inetd,Web服務器httpd等。同時,守護進程完成許多系統任務。
正因為服務器的特點,守護進程在服務器開發上就很重要。
守護進程的創建和使用
守護進程的創建主要分為以下幾個部分:
- 創建子進程,父進程退出
- 在子進程中創建新會話
- 改變當前目錄為根目錄
- 重設文件權限掩碼
- 關閉文件描述符
- 守護進程的退出
1.創建子進程,父進程退出
由於守護進程是脫離控制終端的,因此會在Shell終端里造成一程序已經運行完畢的假象,也就是后台運行。在Linux中父進程先於子進程退出會造成子進程成為孤兒進程,而每當系統發現一個孤兒進程時,就會自動由1號進程(init)收養它,這樣,原先的子進程就會變成init進程的子進程。
if(pid=fork()) exit(0); //是父進程,結束父進程
2.在子進程中創建新會話
由於調用了fork函數時,子進程全盤拷貝了父進程的會話期、進程組、控制終端等,雖然父進程退出了,但會話期、進程組、控制終端等並沒有改變,因此,這還不是真正意義上的獨立開來,而setsid函數能夠使進程完全獨立出來,從而擺脫其他進程的控制。
setsid函數用於創建一個新的會話,並擔任該會話組的組長。調用setsid有下面的3個作用:
- 讓進程擺脫原會話的控制
- 讓進程擺脫原進程組的控制
- 讓進程擺脫原控制終端的控制
其中,會話是一個或多個進程組的集合。通常,一個會話開始於用戶登錄,終止於用戶退出,在此期間該用戶運行的所有進程都屬於這個會話期。
setsid(); //第一子進程成為新的會話組長和進程組長
3.改變當前目錄為根目錄
使用fork創建的子進程繼承了父進程的當前工作目錄。
chdir("/"); //改變工作目錄到/
4.重設文件權限掩碼
由於使用fork函數新建的子進程繼承了父進程的文件權限掩碼,它可能修改守護進程所創建程序的存取位。
所以需要把文件權限掩碼設置為0,可以大大增強該守護進程的靈活性。
umask(0); //重設文件創建掩模
5.關閉文件描述符
用fork函數新建的子進程會從父進程那里繼承一些已經打開了的文件。這些被打開的文件可能永遠不會被守護進程讀寫,但它們一樣消耗系統資源,而且可能導致所在的文件系統無法卸下。
for(i=0;i<MAXFILE;i++) //關閉打開的文件 close(i);
6.守護進程退出
當用戶需要外部停止守護進程運行時,往往會使用 kill命令停止該守護進程。所以,守護進程中需要編碼來實現kill發出的signal信號處理,達到進程的正常退出。
signal(SIGCHLD,SIG_IGN);
例子
//daemon.c
#include <unistd.h> #include <signal.h> #include <sys/param.h> #include <sys/types.h> #include <sys/stat.h> void init_daemon(void) { int pid; int i; if(pid=fork()) exit(0); //是父進程,結束父進程 else if(pid< 0) return(1); setsid(); //第一子進程成為新的會話組長和進程組長 //並與控制終端分離 if(pid=fork()) exit(0); //是第一子進程,結束第一子進程 else if(pid< 0) exit(1); //是第二子進程,繼續 //第二子進程不再是會話組長 for(i=0;i< NOFILE;++i) //關閉打開的文件描述符 close(i); chdir("/"); //改變工作目錄到/ umask(0); //重設文件創建掩模 return; }
//test.c
#include <stdio.h> #include <time.h > void init_daemon(void);//守護進程初始化函數 main() { init_daemon();//初始化為Daemon while(1){ sleep(時間); 處理函數... ; } }
注意,想要關閉后台程序,可以使用"Kill 進程標識符"的命令,查看進程狀態可以使用ps -ef。
參考
http://baike.baidu.com/view/53123.htm
http://blog.csdn.net/zg_hover/article/details/2553321
![]()
Server Develop (七) Linux 守護進程 由 cococo點點 創作,采用 知識共享 署名-非商業性使用-相同方式共享 3.0 中國大陸 許可協議進行許可。歡迎轉載,請注明出處:
轉載自: cococo點點 http://www.cnblogs.com/coder2012