守護進程(Daemon)

分類: C/C++css

 

概念:
     守護進程(Daemon)是運行在後臺的一種特殊進程。它獨立於控制終端而且週期性地執行某種任務或等待處理某些發生的事件。守護進程是一種頗有用的進程。Linux的大多數服務器就是用守護進程實現的。好比,Internet服務器inetd,Web服務器httpd等。同時,守護進程完成許多系統任務。好比,做業規劃進程crond,打印進程lpd等。(這裏的結尾字母d就是Daemon的意思)
建立步驟:
①使進程在後臺運行
  建立子進程父進程退出
if((pid = fork())>0)
   exit(0);
else if(pid<0)
{
    perror("fail to fork");
    exit(-1);
}
②脫離控制終端,登陸會話和進程組(建立新會話)
     有必要先介紹一下Linux中的進程與控制終端,登陸會話和進程組之間的關係:進程屬於一個進程組,進程組號(GID)就是進程組長的進程號(PID)。登陸會話能夠包含多個進程組。這些進程組共享一個控制終端。這個控制終端一般是建立進程的登陸終端。 控制終端,登陸會話和進程組一般是從父進程繼承下來的。咱們的目的就是要擺脫它們,使之不受它們的影響。方法是在第1點的基礎上,調用setsid()使進程成爲會話組長:
   setsid(); 
   說明:當進程是會話組長時setsid()調用失敗。但第一點已經保證進程不是會話組長。
   setsid()調用成功後,進程成爲新的會話組長和新的進程組長,並與原來的登陸會話和進
   程組脫離。因爲會話過程對控制終端的獨佔性,進程同時與控制終端脫離。
    
③禁止進程從新打開控制終端 
   如今,進程已經成爲無終端的會話組長。但它能夠從新申請打開一個控制終端。能夠經過使進程再也不成爲會話組長來禁止進程從新打開控制終端: 
   if(pid=fork()) 
      exit(0);//結束第一子進程,第二子進程繼續(第二子進程再也不是會話組長)
④關閉全部文件描述符
進程從建立它的父進程那裏繼承了打開的文件描述符。如不關閉,將會浪費系統資源,形成進程所在的文件系統沒法卸下以及引發沒法預料的錯誤:
for(i=0;i<=getdtablesize();i++)
close(i);
⑤改變當前工做目錄 
   進程活動時,其工做目錄所在的文件系統不能卸下。通常須要將工做目錄改變到根目錄。對於須要轉儲核心,寫運行日誌的進程將工做目錄改變到特定目錄如/tmp:
chdir("/tmp") ;
⑥重設權限掩碼
     進程從建立它的父進程那裏繼承了文件建立掩碼。它可能修改守護進程所建立的文件的存取位。爲防止這一點,將文件建立掩模清除:
umask(0);
⑦處理SIGCHLD信號 
   處理SIGCHLD信號並非必須的。但對於某些進程,特別是服務器進程每每在請求到來時生成子進程處理請求。若是父進程不等待子進程結束,子進程將成爲殭屍進程(zombie)從而佔用系統資源。若是父進程等待子進程結束,將增長父進程的負擔,影響服務器進程的併發性能。在Linux下能夠簡單地將 SIGCHLD信號的操做設爲SIG_IGN。 
    signal(SIGCHLD,SIG_IGN); 
這樣,內核在子進程結束時不會產生殭屍進程。這一點與BSD4不一樣,BSD4下必須顯式等待子進程結束才能釋放殭屍進程。
無代碼無真相
代碼說明:
init_deamon.c :按照送上面步驟建立守護進程
test.c :調用建立守護進程函數,每隔一秒向/tmp目錄下的print_time文件打印系統時間
  1. /*name: init_deamon.c
  2.  *function:建立一個守護進程
  3.  */
  4. #include <stdio.h>
  5. #include <stdlib.h>
  6. #include <unistd.h> 
  7. #include <signal.h> 
  8. #include <sys/param.h> 
  9. #include <sys/types.h> 
  10. #include <sys/stat.h> 
  11. void init_deamon(void) 
  12. { 
  13.     int pid; 
  14.     int i;
  15.     /* 處理SIGCHLD信號。處理SIGCHLD信號並非必須的。但對於某些進程,特別是服務器進程每每在請求到來時生成子進程處理請求。若是父進程不等待子進程結束,子進程將成爲殭屍進程(zombie)從而佔用系統資源。*/
  16.     if(signal(SIGCHLD,SIG_IGN) == SIG_ERR){
  17.         printf("Cant signal in init_daemon.");
  18.         exit(1);
  19.     }
  20.     if(pid=fork()) 
  21.         exit(0);//是父進程,結束父進程 
  22.     else if(pid< 0){ 
  23.         perror("fail to fork1");
  24.         exit(1);//fork失敗,退出
  25.     }
  26.     //是第一子進程,後臺繼續執行
  27.     setsid();//第一子進程成爲新的會話組長和進程組長 
  28.     //並與控制終端分離 
  29.     if(pid=fork()) 
  30.         exit(0);//是第一子進程,結束第一子進程 
  31.     else if(pid< 0) 
  32.         exit(1);//fork失敗,退出 
  33.     //是第二子進程,繼續 
  34.     //第二子進程再也不是會話組長 
  35.     for(i=0;i< getdtablesize();++i)//關閉打開的文件描述符 
  36.         close(i); 
  37.     chdir("/tmp");//改變工做目錄到/tmp 
  38.     umask(0);//重設文件建立掩模 
  39.     return; 
  40. }
 
  1. /* name     :test.c
  2.  * function    :調用init_deamon函數使進程變成守護進程,而後每一個一秒向/tmp目錄下的print_time文件打印當前時間
  3.  * */
  4. #include <stdio.h> 
  5. #include <time.h> 
  6. void init_deamon(void);//守護進程初始化函數 
  7. void main() 
  8. { 
  9.     FILE *fp; 
  10.     time_t t; 
  11.     init_deamon();//初始化爲Daemon 
  12.     while(1)//每隔一分鐘向test.log報告運行狀態 
  13.     { 
  14.         sleep(1);//睡眠一秒鐘 
  15.         if((fp=fopen("print_time","a")) >=0) 
  16.         { 
  17.             t=time(0); 
  18.             fprintf(fp,"The time right now is : %s",asctime(localtime(&t))); 
  19.             fclose(fp); 
  20.         } 
  21.     }
  22.     return;
  23. }
測試:
 

============2014-4-11 更新============
有些Unix變體提供一個 daemon的C庫函數,實現該功能。BSD和linux均提供這個daemon函數。

  1. #include <unistd.h>
  2. int daemon(int nochdir, int noclose);

摘自:http://blog.chinaunix.net/uid-25365622-id-3055635.htmlhtml

相關文章
相關標籤/搜索