一、 守護進程的概念:linux
守護進程(Daemon)是一種運行在後臺的一種特殊的進程,它獨立於控制終端而且週期性的執行某種任務或等待處理某些發生的事件。因爲在Linux中,每一個系統與用戶進行交流的界面成爲終端,每個今後終端開始運行的進程都會依附於這個終端,這個終端被稱爲這些進程的控制終端,當控制終端被關閉的時候,相應的進程都會自動關閉。可是守護進程卻能突破這種限制,它脫離於終端而且在後臺運行,而且它脫離終端的目的是爲了不進程在運行的過程當中的信息在任何終端中顯示而且進程也不會被任何終端所產生的終端信息所打斷。它從被執行的時候開始運轉,知道整個系統關閉才退出(固然能夠認爲的殺死相應的守護進程)。若是想讓某個進程不由於用戶或中斷或其餘變化而影響,那麼就必須把這個進程變成一個守護進程。shell
二、 守護進程實現的步驟:函數
(1) 建立子進程,父進程退出(使子進程成爲孤兒進程):這是編寫守護進程的第一步,因爲守護進程是脫離終端的,所以完成第一步後就會在shell終端裏形成一個程序已經運行完畢的假象。以後的全部工做在子進程中完成,而用戶在shell終端裏則能夠執行其餘命令,從而在形式上作到了與控制終端脫離。實現的語句以下:if(pid=fork()){exit(0);}是父進程就結束,而後子進程繼續執行。this
(2) 在子進程中建立新的會話(脫離控制終端):編碼
這步是建立守護進程中最重要的一步,雖然實現起來很簡單,可是它的意義很是重要,在這裏使用的是系統函數setsid()來建立一個新的會話,而且擔任該會話組的組長。在這裏有兩個概念須要解釋一下,進程組合會話期。spa
進程組:是一個或多個進程的集合。進程組有進程組ID來惟一標識。除了進程號(PID)以外,進程組ID也是一個進程的必備屬性。每一個進程組都有一個組長進程,其組長進程的進程號等於進程組ID。且該進程組ID不會因組長進程的退出而受到影響。.net
會話週期:會話期是一個或者多個進程的集合。一般一個會話開始於用戶的登陸,終止於用戶的退出,在此期間該用戶運行的全部進程都屬於這個會話期。繼承
Setsid()函數的相關內容:進程
(1) setsid()函數的做用:建立一個新的會話,而且擔任該會話組的組長。具體做用包括:讓一個進程擺脫原會話的控制,讓進程擺脫原進程的控制,讓進程擺脫原控制終端的控制。事件
(2) 建立守護進程要調用setsid()函數的緣由:因爲建立守護進程的第一步是調用fork()函數來建立子進程,再將父進程退出。因爲在調用了fork()函數的時候,子進程拷貝了父進程的會話期、進程組、控制終端等資源、雖然父進程退出了,可是會話期、進程組、控制終端等並無改變,所以,須要用setsid()韓式來時該子進程徹底獨立出來,從而擺脫其餘進程的控制。
(3) 改變當前目錄爲根目錄:
使用fork()建立的子進程是繼承了父進程的當前工做目錄,因爲在進程運行中,當前目錄所在的文件系統是不能卸載的,這對之後使用會形成不少的麻煩。所以一般的作法是讓「/」做爲守護進程的當前目錄,固然也能夠指定其餘的別的目錄來做爲守護進程的工做目錄。
(4) 重設文件權限掩碼:
文件權限掩碼是屏蔽掉文件權限中的對應位。因爲使用fork()函數新建立的子進程繼承了父進程的文件權限掩碼,這就給該子進程使用文件帶了不少的麻煩(好比父進程中的文件沒有執行文件的權限,然而在子進程中但願執行相應的文件這個時候就會出問題)。所以在子進程中要把文件的權限掩碼設置成爲0,即在此時有最大的權限,這樣能夠大大加強該守護進程的靈活性。設置的方法是:umask(0)。
(5) 關閉文件描述符:
同文件權限碼同樣,用fork()函數新建的子進程會從父進程那裏繼承一些已經打開了的文件。這些文件被打開的文件可能永遠不會被守護進程讀寫,若是不進行關閉的話將會浪費系統的資源,形成進程所在的文件系統沒法卸下以及引發預料的錯誤。按照以下方法關閉它們:
for(i=0;i 關閉打開的文件描述符close(i);
(6) 守護進程的退出:
上面創建了守護進程,當用戶須要外部中止守護進程運行時,每每須要使用kill命令來中止該守護進程,因此守護進程中須要編碼來實現kill發出的signal信號處理,達到進程的正常退出。實現該過程的函數是signal函數:
signal(SIGTERM, sigterm_handler);
void sigterm_handler(int arg)
{
//進行相應處理的函數
}。功能是:將一個給定的函數和一個特定的信號聯繫起來,即在收到特定的信號的時候執行相應的函數。
三、守護進程實現的一個簡單的例子:
#include<stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/wait.h>
#define MAXFILE 65535
int main()
{
pid_t pc;
int i,fd,len;
char *buf="this is a dameon \n";
len = strlen(buf);
pc =fork(); //建立一個進程用來作守護進程 if(pc<0) { printf("error fork \n"); exit(1); } else if(pc>0) exit(0); //結束父進程 setsid(); //使子進程獨立1.擺脫原會話控制 2.擺脫原進程組的控制 3.擺脫控制中端的控制 chdir("/"); //改變當前工做目錄,這也是爲了擺脫父進程的影響 umask(0); //重設文件權限掩碼 for(i=0;i<MAXFILE;i++) //關閉文件描述符(常說的輸入,輸出,報錯3個文件), //由於守護進程要失去了對所屬的控制終端的聯繫,這三個文件要關閉 close(i); while(1) { if((fd=open("/tmp/dameon.txt",O_CREAT|O_WRONLY|O_APPEND,0600))<0) { printf("open file err \n"); exit(0); } write(fd,buf,len+1); close(fd); sleep(10); } }