wuhran的Blog-C++,Linux,MySQL,PHP
守護程序是脫離於終端並且在後臺執行的程序。守護程序脫離於終端是為了避免程序在執行過程中的資訊在任何終端上顯示並且程序也不會被任何終端所產生的終端資訊所打斷。
守護程序,也就是通常說的Daemon程序,是Linux中的後臺服務程序。它是一個生存期較長的程序,通常獨立於控制終端並且週期性地執行某種任務或等待處理某些發生的事件。守護程序常常在系統引導裝入時啟動,在系統關閉時終止。Linux系統有很多守護程序,大多數服務都是通過守護程序實現的,同時,守護程序還能完成許多系統任務,例如,作業規劃程序crond、列印程序lqd等(這裡的結尾字母d就是Daemon的意思)。
由於在Linux中,每一個系統與使用者進行交流的介面稱為終端,每一個從此終端開始執行的程序都會依附於這個終端,這個終端就稱為這些程序的控制終端,當控制終端被關閉時,相應的程序都會自動關閉。但是守護程序卻能夠突破這種限制,它從被執行開始運轉,直到整個系統關閉時才退出。如果想讓某個程序不因為使用者或終端或其他地變化而受到影響,那麼就必須把這個程序變成一個守護程序。
建立一個簡單的守護程序:
1、建立子程序,父程序退出
這是編寫守護程序的第一步。由於守護程序是脫離控制終端的,因此,完成第一步後就會在Shell終端裡造成一程式已經執行完畢的假象。之後的所有工作都在子程序中完成,而使用者在Shell終端裡則可以執行其他命令,從而在形式上做到了與控制終端的脫離。
在Linux中腹程序先於子程序退出會造成子程序成為孤兒程序,而每當系統發現一個孤兒程序是,就會自動由1號程序(init)收養它,這樣,原先的子程序就會變成init程序的子程序。
2、在子程序中建立新會話
這個步驟是建立守護程序中最重要的一步,雖然它的實現非常簡單,但它的意義卻非常重大。在這裡使用的是系統函式setsid,在具體介紹setsid之前,首先要了解兩個概念:程序組和會話期
程序組:是一個或多個程序的集合。程序組有程序組ID來唯一標識。除了程序號(PID)之外,程序組ID也是一個程序的必備屬性。每個程序組都有一個組長程序,其組長程序的程序號等於程序組ID。且該程序組ID不會因組長程序的退出而受到影響。
會話週期:會話期是一個或多個程序組的集合。通常,一個會話開始與使用者登入,終止於使用者退出,在此期間該使用者執行的所有程序都屬於這個會話期。
接下來就可以具體介紹setsid的相關內容:
(1)setsid函式作用:
setsid函式用於建立一個新的會話,並擔任該會話組的組長。呼叫setsid有下面的3個作用:
讓程序擺脫原會話的控制
讓程序擺脫原程序組的控制
讓程序擺脫原控制終端的控制
那麼,在建立守護程序時為什麼要呼叫setsid函式呢?由於建立守護程序的第一步呼叫了fork函式來建立子程序,再將父程序退出。由於在呼叫了fork函式時,子程序全盤拷貝了父程序的會話期、程序組、控制終端等,雖然父程序退出了,但會話期、程序組、控制終端等並沒有改變,因此,還還不是真正意義上的獨立開來,而setsid函式能夠使程序完全獨立出來,從而擺脫其他程序的控制。
3、改變當前目錄為根目錄
這一步也是必要的步驟。使用fork建立的子程序繼承了父程序的當前工作目錄。由於在程序執行中,當前目錄所在的檔案系統(如“/mnt/usb”)是不能解除安裝的,這對以後的使用會造成諸多的麻煩(比如系統由於某種原因要進入但使用者模式)。因此,通常的做法是讓"/"作為shohujincheng 的當前工作目錄,這樣就可以避免上述的問題,當然,如有特殊需要,也可以把當前工作目錄換成其他的路徑,如/tmp。改變工作目錄的常見函式式chdir。
4、重設檔案許可權掩碼
檔案許可權掩碼是指遮蔽掉檔案許可權中的對應位。比如,有個檔案許可權掩碼是050,它就遮蔽了檔案組擁有者的可讀與可執行許可權。由於使用fork函式新建的子程序繼承了父程序的檔案許可權掩碼,這就給該子程序使用檔案帶來了諸多的麻煩。因此,把檔案許可權掩碼設定為0,可以大大增強該守護程序的靈活性。設定檔案許可權掩碼的函式是umask。在這裡,通常的使用方法為umask(0)。
5、關閉檔案描述符
同文件許可權碼一樣,用fork函式新建的子程序會從父程序那裡繼承一些已經打開了的檔案。這些被開啟的檔案可能永遠不會被守護程序讀寫,但它們一樣消耗系統資源,而且可能導致所在的檔案系統無法卸下。
在上面的第二步之後,守護程序已經與所屬的控制終端失去了聯絡。因此從終端輸入的字元不可能達到守護程序,守護程序中用常規方法(如printf)輸出的字元也不可能在終端上顯示出來。所以,檔案描述符為0、1和2 的3個檔案(常說的輸入、輸出和報錯)已經失去了存在的價值,也應被關閉。通常按如下方式關閉檔案描述符:
===============================
for(i=0;i<MAXFILE;i++)
close(i);
===============================
這樣,一個簡單的守護程序就建立起來了。
實現守護程序的完整例項(每隔10s在/tmp/dameon.log中寫入一句話):
=====================================================================
#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(); //第二步
chdir("/"); //第三步
umask(0); //第四步
for(i=0;i<MAXFILE;i++) //第五步
close(i);
while(1){
if((fd=open("/tmp/dameon.log",O_CREAT|O_WRONLY|O_APPEND,0600))<0){
perror("open");
exit(1);
}
write(fd,buf,len+1);
close(fd);
sleep(10);
}
}