之前發過一篇守護進程的文章,但是解析的不夠詳細,這次,詳細來解釋守護進程的一些概念和特性。
概念:
後台運行、沒有控制端與之相連的進程。獨立於控制終端,通常周期性的執行某種任務。
Why survival:
Linux的大多數服務器是用守護進程的方式實現,例如:Internet服務器的inted,Web服務器的http等。Linux守護進程類似Windowns的系統服務。
daemon特性:
1.讓進程在後台執行,方法是fork產生一個子進程,然後父進程退出。
2.調用setsid創建一個新對話期。
控制端、登錄會話和進程組通常是從父進程繼承來的。
守護進程要擺脫它們,不受它們的影響,其方法是調用setid使進程成長為一個會話組長。
注:當進程是會話組長時,調用setid會失敗,但第一點已經保證進程不是會話組長。
setid調用成功後,進程成為新的會話組長和進程組長,並與原來的登陸會話和進程組脫離,由於會話過程對控制終端的獨占性,進程同時與控制終端脫離。
3.禁止進程重新打開控制終端。
以上完成後,進程已經成為一個無終端的會話組長,但是它可以重新申請打開一個終端,為了避免這種情況的發生,可以通過使進程不再是會話組長來實現,再一次fork創建新的進程,使調用fork的進程退出。
4.關閉不再需要的文件描述符。
創建的新子進程從父進程繼承打開的文件描述符。如不關閉,將會浪費系統資源,造成進程所在的文件系統無法卸下以及引起無法預料的結果,先得到最高文件描述值,然後用一個循環程序,關閉0到最高文件描述符值的所有文件描述符。
5.將當前目錄更改為根目錄。
當守護進程當前工作目錄在一個裝配文件系統時,改文件系統不能被拆卸。一般需要將工作目錄改為根目錄。
6.將文件創建時使用的屏蔽字設置為0。
進程從創建它的父進程那裡繼承的文件創建屏蔽字可能會拒絕某些許可權。為防止這一點,使用umask(0)將屏蔽字清零。
7.處理SIGCHLD信號。
這一點不是必須的,但是對於某些進程,特別是服務器進程往往在請求到來時生成子進程處理請求,如果父進程不等待子進程結束,子進程將成為僵屍進程(zombie),從而占用系統資源。如果父進程等待子進程結束,將增加父進程的負擔,影響服務器進程的並發性能。
在Linux下可以簡單的將SIGCHLD信號的操作設為SIG_IGN,這樣子進程結束時就不會產生僵屍進程。
以上為文字敘述,下面我們用代碼來解釋:
# include <unistd.h> # include <sys/types.h> # include <signal.h> # include <sys/param.h> # include <sys/stat.h> # include <time.h> # include <syslog.h> # include <stdio.h> int init_daemon(void) { int pid; int i; /*忽略終端IO信號,STOP信號*/ signal(SIGTTOU, SIG_IGN); signal(SIGTTIN, SIG_IGN); signal(SIGTSTP, SIG_IGN); signal(SIGHUP, SIG_IGN); pid = fork(); if(pid > 0) {/*結束父進程,使子進程成為後台進程*/ exit(0); } else if(pid < 0) { return -1; } /*建立一個新的進程組,在這個新的進程組中,子進程成為這個進程組的首進程,以使該進程 脫離所有終端*/ setsid(); /*再次新建一個子進程,退出父進程,保證該進程不是進程組長,同時讓該進程無法再打開一個 新的終端*/ pid = fork(); if(pid > 0) { exit(0); } else if(pid < 0) { return -1; } /*關閉所有父進程繼承的不再需要的文件描述符*/ for(i = 0; i < NOFILE; close(i++)) { ; } /*改變工作目錄,使得進程不與任何文件系統聯系*/ chdir("/"); /*將文件屏蔽字設置為0*/ umask(0); /*忽略SIGCHLD信號*/ signal(SIGCHLD, SIG_IGN); return 0; } int main(void) { time_t now; init_daemon(); syslog(LOG_USER | LOG_INFO, "Test daemon \n"); while(1) { sleep(8); time(&now); syslog(LOG_USER | LOG_INFO, "system time : \t%s\t\t\n", ctime(&now)); } return 0; }
但是要對Linux進行一些配置:
使用syslog()函數前,首先配置/etc/syslog.conf,在該文件最後末尾加上:
user.* /var/log/test.log
然後重啟syslog服務。
/etc/init.d/syslog stop
/etc/init.d/syslog start
運行結果:ps -ef
本文出自 “_Liang_Happy_Life__Dream” 博客,請務必保留此出處http://liam2199.blog.51cto.com/2879872/1241726