守护进程

守护进程(daemon)是生存期较长的一种进程,在系统开启时启动,关闭时才终止,没有控制终端在后台运行。

守护进程结构:

依赖操作系统实现,以超级用户特权运行,无控制终端,无命令行,大多数守护进程的父进程是init进程。

常见的守护进程:

init:负责启动各运行层次特定的系统任务。

kswapd:页面调出守护进程,通过脏页面以低速写到磁盘上从而使这些页面在需要时可回收使用。

bdflushkupdated:将高速缓存页面冲洗到磁盘上。

portmap:将远程过程调用映射为网络端口号的服务。

syslog:可由帮助操作人员把系统消息记入日志的任何程序使用。

inited:侦听系统网络接口,以便取得来自网络的对各种网络服务进程的请求。

编写守护进程:步骤:

1. 创建子进程,父进程退出:所有工作在子进程中进行,形式上脱离控制终端。

2. 在进程中创建新会话:setsid()函数,使子进程完全独立,脱离控制。

3. 修改当前目录为根目录:chdir()函数,防止占用可卸载的文件系统,也可换成其他路径。

4. 重设文件权限掩码:unmask函数,防止继承的文件创建屏蔽字拒绝某些权限,增加守护进程灵活性

5. 关闭不再需要的文件描述符:继承的打开文件不会用到,浪费系统资源无法卸载。

for (i = 0 ; i  关闭打开的文件描述符close ( i ))

范例程序如下:

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. void daemonize(const char *cmd)  
  2. {  
  3.     int                 i, fd0, fd1, fd2;  
  4.     pid_t               pid;  
  5.     struct rlimit       rl;  
  6.     struct sigaction    sa;  
  7.     /* 将文件模式屏蔽位设置为0 */  
  8.     umask(0);  
  9.    
  10.     /* 获取最大文件描述符值,用于关闭不再需要的文件描述符 */  
  11.     if (getrlimit(RLIMIT_NOFILE, &rl) < 0)  
  12.         err_quit("%s: can't get file limit", cmd);  
  13.    
  14.     /*  使子进程称为新会话的首进程,并失去控制终端 */  
  15.     if ((pid = fork()) < 0)  
  16.         err_quit("%s: can't fork", cmd);  
  17.     else if (pid != 0) /* parent */  
  18.         exit(0);  
  19.     setsid();  
  20.    
  21.     /* 使子进程在一个孤儿进程组中,不再是会话首进程,于是不会有机会分配到一个控制终端 */  
  22.     sa.sa_handler = SIG_IGN;  
  23.     sigemptyset(&sa.sa_mask);  
  24.     sa.sa_flags = 0;  
  25.     if (sigaction(SIGHUP, &sa, NULL) < 0)  
  26.         err_quit("%s: can't ignore SIGHUP");  
  27.     if ((pid = fork()) < 0)  
  28.         err_quit("%s: can't fork", cmd);  
  29.     else if (pid != 0) /* parent */  
  30.         exit(0);  
  31.    
  32.     /* 将当前工作目录更改为根目录,使装配文件可拆卸 */  
  33.     if (chdir("/") < 0)  
  34.         err_quit("%s: can't change directory to /");  
  35.    
  36.     /*  关闭不再需要的文件描述符 */  
  37.     if (rl.rlim_max == RLIM_INFINITY)  
  38.         rl.rlim_max = 1024;  
  39.     for (i = 0; i < rl.rlim_max; i++)  
  40.         close(i);  
  41.    
  42.     /*  使文件描述符0、1和2与/dev/null关联 */  
  43.     fd0 = open("/dev/null", O_RDWR);  
  44.     fd1 = dup(0);  
  45.     fd2 = dup(0);  
  46.    
  47.     /* 初始化日志文件 */  
  48.     openlog(cmd, LOG_CONS, LOG_DAEMON);  
  49.     if (fd0 != 0 || fd1 != 1 || fd2 != 2) {  
  50.         syslog(LOG_ERR, "unexpected file descriptors %d %d %d",  
  51.           fd0, fd1, fd2);  
  52.         exit(1);  
  53.     }  
  54. }   

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. //创建一个守护进程监视系统所有运行的进程  
  2. #include<unsitd.h>  
  3. #include<stdio.h>  
  4. #include<stdlib.h>  
  5. #include<signal.h>  
  6. #include<sys/types.h>  
  7. #include<sys/resource.h>  
  8. #include<sys/stat.h>  
  9.   
  10. //创建一个守护进程  
  11. void init ()  
  12. {  
  13.     pid_t pid ;  
  14.     int i ;  
  15.     struct rlimit rl ; //获取进城资源的限制  
  16.     struct sigaction sa ;  
  17.   
  18.   
  19.     if(getrlimit(RLIMIT_NOFILE , &rl) < 0)   
  20.     {  
  21.         printf("con't get file limit") ;  
  22.     }  
  23.     if((pid = fork()) < 0)  
  24.         err_quit("%s: can't fork" , cmd);  
  25.     else if (pid != 0)  
  26.         exit(0); //父进程退出  
  27.     //子进程继续执行  
  28.     setsid();  
  29.       
  30.     //防止子进程(组长)获取控制终端  
  31.     if((pid = fork()) < 0)  
  32.         err_quit("%s:can't fork", cmd);  
  33.     else if (pid != 0)  
  34.         exit(0);   
  35.     //第二子进程继续运行,不再是会话组组长  
  36.   
  37.     //关闭打开的文件描述符  
  38.     if(rl.rlim_max == RLM_INFINITY)  
  39.         rl.rlim_max = 1024;  
  40.     for(i = 0; i < rl.rlim_max; i++)  
  41.         close(i);  
  42.     chdir("/tmp"); //切换到工作目录  
  43.     unmask(0); //重设文件创建掩码  
  44.     return;  
  45. }  
  46. int main ()  
  47. {  
  48.     FILE *fp ;  
  49.     FILE *fstream;  
  50.     signal(SIGCHLD, SIG_IGN); //忽略子进程信号,防止出现僵尸进程  
  51.       
  52.     init() ; //创建守护进程  
  53.     while(1)  
  54.     {  
  55.     //进程id,user:父进程,comm:进程名,lstart:进程开始时间,etime:进程持续时间  
  56.         fstream = open("ps -eo pid,user,comm,lstart,etime>time.txt","r");  
  57.          if(fstream==NULL)    
  58.         {    
  59.             //在打开或者创建error.log成功的情况下,写入错误(使用errno时失败)    
  60.             if((fp = fopen("error.log""a+")) != NULL)    
  61.             {    
  62.                 fprintf(fp, "%s\n""执行命令失败");    
  63.                 fclose(fp);    
  64.             }    
  65.             else    
  66.                exit(1);  //写入错误失败,则终止程序推出并关闭所有进程    
  67.         }    
  68.         else    
  69.           pclose(fstream); //关闭popen打开的I/O流    
  70.         sleep(120);   //设置成5分钟获取一次系统进程情况    
  71.     }  
  72.     return 0;  
  73. }  

守护进程报告出错情况:

守护进程没有控制终端,所以不是简单的写到标准输出上,而是使用syslog设施,有三种方法产生日至消息:1)内核例程调用log函数;2)进程调用syslog函数产生日志消息;3)此主机上的一个用户进程可将日志消息发向UDP端口514,然后,syslogd守护进程读取三种格式的日志信息,根据配置文件(一般是/etc/syslog.conf)决定不同种类的信息应送往何处,守护进程通常使用syslog函数产生日志信息。

#include <syslog.h>

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

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

void closelog(void);

int setlogmask(int maskpri);

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值