守护进程

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

守护进程结构:

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

常见的守护进程:

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

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

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

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

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

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

编写守护进程:步骤:

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

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

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

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

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

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

范例程序如下:

void daemonize(const char *cmd)
{
    int                 i, fd0, fd1, fd2;
    pid_t               pid;
    struct rlimit       rl;
    struct sigaction    sa;
    /* 将文件模式屏蔽位设置为0 */
    umask(0);
 
    /* 获取最大文件描述符值,用于关闭不再需要的文件描述符 */
    if (getrlimit(RLIMIT_NOFILE, &rl) < 0)
        err_quit("%s: can't get file limit", cmd);
 
    /*  使子进程称为新会话的首进程,并失去控制终端 */
    if ((pid = fork()) < 0)
        err_quit("%s: can't fork", cmd);
    else if (pid != 0) /* parent */
        exit(0);
    setsid();
 
    /* 使子进程在一个孤儿进程组中,不再是会话首进程,于是不会有机会分配到一个控制终端 */
    sa.sa_handler = SIG_IGN;
    sigemptyset(&sa.sa_mask);
    sa.sa_flags = 0;
    if (sigaction(SIGHUP, &sa, NULL) < 0)
        err_quit("%s: can't ignore SIGHUP");
    if ((pid = fork()) < 0)
        err_quit("%s: can't fork", cmd);
    else if (pid != 0) /* parent */
        exit(0);
 
    /* 将当前工作目录更改为根目录,使装配文件可拆卸 */
    if (chdir("/") < 0)
        err_quit("%s: can't change directory to /");
 
    /*  关闭不再需要的文件描述符 */
    if (rl.rlim_max == RLIM_INFINITY)
        rl.rlim_max = 1024;
    for (i = 0; i < rl.rlim_max; i++)
        close(i);
 
    /*  使文件描述符0、1和2与/dev/null关联 */
    fd0 = open("/dev/null", O_RDWR);
    fd1 = dup(0);
    fd2 = dup(0);
 
    /* 初始化日志文件 */
    openlog(cmd, LOG_CONS, LOG_DAEMON);
    if (fd0 != 0 || fd1 != 1 || fd2 != 2) {
        syslog(LOG_ERR, "unexpected file descriptors %d %d %d",
          fd0, fd1, fd2);
        exit(1);
    }
} 

//创建一个守护进程监视系统所有运行的进程
#include<unsitd.h>
#include<stdio.h>
#include<stdlib.h>
#include<signal.h>
#include<sys/types.h>
#include<sys/resource.h>
#include<sys/stat.h>

//创建一个守护进程
void init ()
{
	pid_t pid ;
	int i ;
	struct rlimit rl ; //获取进城资源的限制
	struct sigaction sa ;


	if(getrlimit(RLIMIT_NOFILE , &rl) < 0) 
	{
		printf("con't get file limit") ;
	}
	if((pid = fork()) < 0)
		err_quit("%s: can't fork" , cmd);
	else if (pid != 0)
		exit(0); //父进程退出
	//子进程继续执行
	setsid();
	
	//防止子进程(组长)获取控制终端
	if((pid = fork()) < 0)
		err_quit("%s:can't fork", cmd);
	else if (pid != 0)
		exit(0); 
	//第二子进程继续运行,不再是会话组组长

	//关闭打开的文件描述符
	if(rl.rlim_max == RLM_INFINITY)
		rl.rlim_max = 1024;
	for(i = 0; i < rl.rlim_max; i++)
		close(i);
	chdir("/tmp"); //切换到工作目录
	unmask(0); //重设文件创建掩码
	return;
}
int main ()
{
	FILE *fp ;
	FILE *fstream;
	signal(SIGCHLD, SIG_IGN); //忽略子进程信号,防止出现僵尸进程
	
	init() ; //创建守护进程
	while(1)
	{
	//进程id,user:父进程,comm:进程名,lstart:进程开始时间,etime:进程持续时间
		fstream = open("ps -eo pid,user,comm,lstart,etime>time.txt","r");
		 if(fstream==NULL)  
        {  
            //在打开或者创建error.log成功的情况下,写入错误(使用errno时失败)  
            if((fp = fopen("error.log", "a+")) != NULL)  
            {  
                fprintf(fp, "%s\n", "执行命令失败");  
                fclose(fp);  
            }  
            else  
               exit(1);  //写入错误失败,则终止程序推出并关闭所有进程  
        }  
        else  
          pclose(fstream); //关闭popen打开的I/O流  
        sleep(120);   //设置成5分钟获取一次系统进程情况  
	}
	return 0;
}

守护进程报告出错情况:

守护进程没有控制终端,所以不是简单的写到标准输出上,而是使用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);



  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值