守護進程


1什么叫做守護進程

守護進程一般在系統引導裝入的時候啟動,在系統關閉的時候關閉,因為他們沒有控制終端,所以說他們是后台運行的,用來執行一些日長的任務

利用ps -axj可以查看,其中a是查看其他的用戶所擁有的進程,x顯示沒有控制終端的進程狀態,-j顯示與作業有關的信息,主要是第一行的信息

這個ps命令要正確 的打印,系統必須支持會話,否則不能正確的顯示,父進程是0的通常是內核進程,內核進程的生命周期存在於系統的整個生命周期中,他們以超級用戶權限運行,沒有控制終端,不能使用命令行

如何判斷是否是守護進程,當TPGID=-1的時候就是守護進程,comman命令加了[]就是系統級的守護進程,沒有加[]就是用戶級的守護進程,要注意,init並不是一個內核級的守護進程,他是用戶級的守護進程的父進程

我們如何判定是否使用內核守護進程:我們使用一個內核組件,卻不被用戶進程的上下文所調用,並且是常駐內存,我們就應該使用內核守護進程

使用守護進程的大體原則:

如果一個進程永遠都是以后台方式啟動,並且不能受到Shell退出影響而退出,一個正統的做法是將其創建為守護進程(daemon)。守護進程值得是系統長期運行的后台進程,類似Windows服務。守護進程信息通過ps –a無法查看到,需要用到–x參數,當使

用這條命令的時候,往往還附上-j參數以查看作業控制信息,其中TPGID一欄為-1就是守護進程。

2對於守護進程的編程規則

  
  
  
          
  1. #include "apue.h"
  2. #include <syslog.h>
  3. #include <fcntl.h>
  4. #include <sys/resource.h>
  5. void daemonize(const char *cmd)
  6. {
  7. int i,fd0,fd1,fd2;
  8. pid_t pid;
  9. struct rlimit r1;
  10. struct sigaction sa;
  11. umask(0);
  12. if(getrlimit(RLIMIT_NOFILE,&r1) < 0)
  13.  err_quit("%s:can't get file limit",cmd);
  14. if((pid = fork())<0)
  15.  err_quit("%s:can't fork",cmd);
  16. else if(pid != 0)
  17.  exit(0);
  18. setsid();
  19. sa.sa_handler = SIG_IGN;
  20. sigemptyset(&sa.sa_mask);
  21. sa.sa_flags = 0;
  22. if(sigaction(SIGHUP,&sa,NULL) < 0)
  23.  err_quit("%s:can't ignore SIGHUP",cmd);
  24. if((pid = fork()) < 0)
  25.  err_quit("%s:can't fork",cmd);
  26. else if(pid != 0)
  27. {
  28. exit(0);
  29. }
  30. if(chdir("/") < 0)
  31.  err_quit("%s:can't change directory to /",cmd);
  32. if(r1.rlim_max == RLIM_INFINITY)
  33. r1.rlim_max = 1024;
  34. for(i = 0; i < r1.rlim_max;i++)
  35.  close(i);
  36. fd0 = open("/dev/null",O_RDWR);
  37. fd1 = dup(0);
  38. fd2 = dup(0);
  39. openlog(cmd,LOG_CONS,LOG_DAEMON);
  40. if(fd0 != 0|| fd1 != 1||fd2 != 2)
  41. {
  42. syslog(LOG_ERR,"unexpected file descriptors %d %d %d",fd0,fd1,fd2);
  43. exit(0);
  44. }
  45. }
  46. int main()
  47. {
  48. daemonize("my ");
  49. sleep(10);
  50. return 0;
  51. }

將一個進程變成一個守護進程的方法

(1)首先應該改變的是文件模式屏蔽字,因為在原本的進程上下文中,文件屏蔽字是不一定符合規范的,而且守護進程一般需要創建一個具有特定要求的屏蔽字,所以應該自己設置一個合理的屏蔽字,如果有更加嚴格的要求一般將文件模式設置為007

(2)調用fork,進行創建一個新的子進程,為什么要這么做第一,如果在shell中這樣啟動一個程序,當父進程exit的時候,會讓shell認為此程序已經執行完畢第二,這樣保證了這個進程不是一個子進程,這是使用setsid的先決條件

(3)調用setsid來進行設置一個新的會話,在創建會話的時候為了保證不分配一個控制終端,通常會在fork一次,這樣就一定這個進程不是控制終端進程(其實在第一次fork的時候,並且使用了setsid的時候就確定了一定不是控制終端)這樣做其實是為了更加確定(可以這樣理解)

(4)更改當前的工作目錄成為根目錄,因為如果不更改為根目錄,本來工作的目錄其實就要一直被掛載,這在某些系統中,顯然是這樣做到,因為有可能這個操作系統會被刪除

(5)進行所有的文件描述符的關閉

(6)某些守護進程打開/dev/null等,使其映射到0,1,2

關於程序的運行的結果顯示

3守護進程出錯記錄

首先我們進行syslog的介紹

 syslog是一種工業標准的協議,可用來記錄設備的日志。在UNIX系統,路由器、交換機等網絡設備中,系統日志(System Log)記錄系統中任何時間發生的大小事件。管理者可以通過查看系統記錄,隨時掌握系統狀況。UNIX的系統日志是通過syslogd這個進程記錄系統有關事件記錄,也可以記錄應用程序運作事件。通過適當的配置,我們還可以實現運行syslog協議的機器間通信,通過分析這些網絡行為日志,藉以追蹤掌握與設備和網絡有關的狀況。

因為守護進程是沒有控制終端的,所以一般不能要求守護進程將出錯記錄寫到控制台上,當然也不能寫到一個文件中,如果每個守護進程都寫到一個文件中,則無疑再用的時候是很麻煩的


這是日志系統的主要設施,這個設施被稱為syslog設施,與用戶進程調用syslog不是一個東西,三種可以產生日志的方法

(1)用戶守護進程調用syslog函數產生日志消息,這些消息被送往UNIX域數據報套接字(這是一個設備,目前先了解為就是一個設施)然后接下來syslog是不產生UDP數據報的,要注意

(2)通過tcp/ip網絡在或者不在此系統上的進程發送消息到UDP端口54

(3)內核通過log發送到klog

其中syslogd這個守護進程讀取這三種格式的日志消息,並且根據/etc/syslog.conf發送,該文件決定了不同種類的消息應該送向何處,列如緊急消息可送往系統管理員,而警告信息可以送往一個文件

該syslog整個設備的接口(這里的接口指的是操作整個syslog的接口,可以往/dev/log或者UDP或者klog里面寫,總之就是整個syslog的寫入接口,但是可以根據選項選擇怎樣寫,寫什么樣的小設備

主要有四個接口

#include<syslog.h>

void openlog(const char* ident,int option,int facility);

ident:一般是程序的名字,自動追加到每則日志消息中

option:



打開日志系統,其中這個是可選的,如果沒有調用openlog,則在第一次調用syslog的時候,自動調用openlog。    

facility:

facility可以讓配置文件說明,來自不同設施的消息將以不同的方式進行處理

注意:如果不調用openlog,或者以facility為0來調用,那么在調用syslog,可將facility作為priority參數的一個不分進行說明

void syslog(int priority,const char *format,....);

priority:是facility和level的組合,其中level可以是

format:以及其他的所有參數傳至vsprintf函數進行格式話,在format中,每個出現的%m字符都被替換成和errno對應的字符串

void closelog(void );

用來關閉被用於與syslogd函數通信的描述符

int setlogmask(int makdpri);

設置屏蔽字,如果被設置,則不進行屏蔽,優先級屏蔽字

列如,我們提供一個范列

4單實例守護進程

什么叫做單實例守護進程

因為出於需要,系統在某個時間只需要一個守護進程運行,列如有的守護進程需要排他性的訪問一個設備;比如說,cron進程在具體 的時間內運行某一個進程,此進程是守護進程,如果運行多個這樣子的守護進程,則會在相同的時間內運行多個一樣的程序,造成混輪,所以這個cron進程需要字任意一個時間內運行一個守護進程!!

守護進程采用文件-和記錄鎖實現了單實例守護進程,此方法假設,守護進程都需要創建一個文件,並且在第一個守護進程創建文件之后就對整個文件進行加鎖,使其他的相同的守護進程不能自進行此文件的加鎖,這樣就實現了守護進程的單實例運行

  
  
  
          
  1. #include "unistd.h"
  2. #include "stdlib.h"
  3. #include "fcntl.h"
  4. #include "syslog.h"
  5. #include "string.h"
  6. #include "errno.h"
  7. #include "stdio.h"
  8. #include <sys/stat.h>
  9. #define LOCKFILE "var/run/daemon.pid"
  10. #define LOCKMODE (S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)
  11. extern int lockfile(int);
  12. int already_running(void)
  13. {
  14. int fd;
  15. char buf[16];
  16. fd = open(LOCKFILE,O_RDWR|O_CREAT,LOCKMODE);
  17. if(fd < 0)
  18. {
  19. syslog(LOG_ERR,"can't open :%s %s",LOCKFILE,strerror(errno));
  20. exit(1);
  21. }
  22. if(lockfile(fd) < 0)
  23. {
  24. if(errno == EACCES || errno ==EAGAIN)
  25. {
  26. close(fd);
  27. return(1);
  28. }
  29. syslog(LOG_ERR,"can't lock %s:%s",LOCKFILE,strerror(errno));
  30. exit(1);
  31. }
  32. ftruncate(fd,0);
  33. sprintf(buf,"%ld",(long)getpid());
  34. write(fd,buf,strlen(buf)+1);
  35. return 0;
  36. }
  37. int main()
  38. {
  39. already_running();
  40. return 0;
  41. }

如以上的程序,先創建一個文件夾,並且在運用此函數時候鎖住該文件,如果再有守護進程調用的時候,則進行鎖住,並且將其寫入文件,strerror是將錯誤標志轉換成字符串

5守護進程的慣例

在unix系統中,通常的守護進程設計通常是如此設計

(1)如果守護進程使用鎖文件,則該鎖文件通常位於/var/run目錄中。然而需要主義的是,在該目錄創建文件通常需要超級用戶的權限,鎖文件的名字通常是name.pid,例如cron守護進程鎖文件的名字是/var/run/crond.pid

(2)如果守護進程支持配置選項,那么該配置文件一般是放在/etc上的,文件名字一般是name.cond,name是該守護進程或服務的名字,

(3)守護進程可以使用命令啟動,但是該啟動命令一班是在系統初始化 的腳本中進行的,如果守護進程終止,應當自動進行重啟,並且如果一個守護進程更新了配置文件,則應該重新啟動

(4)為了避免當更改配置文件,需要停止在啟動進程的時候,某些進程將捕捉SIGHUP信號,當接受到此信號的時候,重新讀取配置文件。因為守護進程不與終端結合,他們或者是沒有控制終端的會話首進程,或者是孤兒進程組的成員,所以守護進程沒有里有期望接受SIGHUP,因此,守護進程可以重復使用SIGHUP









免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM