zoukankan      html  css  js  c++  java
  • 【Linux开发基础】Linux守护服务进程(Daemon service)编程

    作者:gnuhpc
    出处:http://www.cnblogs.com/gnuhpc/

    1.简介:守护服务进程指的是在后台运行,起到提供服务的进程。

    2.步骤:

    1)将进程放入后台:

    这里利用了fork为当前进程创建一份拷贝(即子进程),然后令父进程退出后子进程被init进程(系统初始化进程,是所有进程的父进程)接管时会将进程放入后台这个特点。

    i=fork();
    
    	if (i<0) exit(1); /* fork error */
    
    	if (i>0) exit(0); /* parent exits */
    
    	/* child (daemon) continues */

    2)进程独立化

    每一个进程都从它连接的终端获取信号,并且它也继承了其父进程的控制终端,一个守护进程不应该从开启它的主进程中获取信号,因此要设法从与其连接的控制终端中脱离出来。在unix中,会话(session)由一个或多个进程组的组成,进程组由一个或多个进程组成,会话与控制终端是一一对应的关系。

    方法是:使用setsid将进程放入新的一个会话中,这个进程是这个新会话的leader,也是这个新进程组的leader,并且没有控制终端。这就达到了分离进程与控制终端的作用。

    setsid();//use setpgrp() can also work

    3)重定向标准IO描述符

    在创建子进程时,打开的描述符会被子进程继承,这会造成资源的不必要浪费,所以应该在fork之前或者在子进程刚启动时把不需要的描述符关闭,但是要将三个标准IO描述符:标准输入(0)、标准输出(1)、标准错误(2),连接到一个没有任何不良影响的IO设备上,我们的做法是关闭所有的文件描述符,open打开/dev/null 这个设备,使其具有文件描述符0,也就是标准输入,然后使用dup将标准输出和标准错误都重定向到这个设备上去:

    for (i=getdtablesize();i>=0;--i) close(i); /* close all descriptors */
    
    i=open("/dev/null",O_RDWR); /* open stdin */
    
    dup(i); /* stdout */
    
    dup(i); /* stderr */

    4)设置umask

    安全起见,我们常常通过设置umask对创建文件的读写进行控制,根据Daemon在不同场景的需要我们可以设置不同的umask,满足权限控制(创建的新文件的权限是umask的补码)的要求,在某些文献上写umask设置为0,注意这是开放所有权限,请确定这样做不会带来风险:

    umask(027);

    5)设置运行目录

    为了保证运行时的环境,我们通常要设定运行时相对的根目录,有些文档上统一设置为系统根目录,请确定这样做是否符合你的应用场景:

    chdir("/servers/");

    6)设置单例运行

    大多数Daemon service程序都希望在同一时刻在内存中只有一个实例,那么常使用文件锁来满足这个需求,在这个文件锁中,我们写入这个进程的进程号pid:

    lfp=open("exampled.lock",O_RDWR|O_CREAT,0640);
    
    if (lfp<0) exit(1); /* can not open */
    
    if (lockf(lfp,F_TLOCK,0)<0) exit(0); /* can not lock */
    
    /* only first instance continues */
    
    sprintf(str,"%d/n",getpid());
    
    write(lfp,str,strlen(str)); /* record pid to lockfile */

    7)处理信号

    一个进程可以从用户或者一个进程接收信号并对其进行相应的处理,使用signal(提倡使用sigaction)绑定处理函数。

    8)写日志

    每个Daemon service都需要有日志记录功能以便用户查阅,有下列几种基本方法:

    a)重定向所有输出到标准IO:在程序启动的时候使用shell的重定向功能。

    b)log文件:打开一个文件并写入。

    c)rsyslogd守护进程:使用这个系统守护进程,在/etc/rsyslog.conf进行配置完成。具体方法请参见:http://www.rsyslog.com/

    3.实例:

    /*
    
    * =====================================================================================
    
    *
    
    *       Filename:  daemon.c
    
    *
    
    *    Description:
    
                        To test daemon:	ps -ef|grep daemonexampled (or ps -aux on BSD systems)
    
                        To test log:	tail -f /tmp/daemonexampled.log
    
                        To test signal:	kill -HUP `cat /tmp/daemonexampled.lock`
    
                        To terminate:	kill `cat /tmp/daemonexampled.lock`
    
    *
    
    *        Version:  1.0
    
    *        Created:  10/25/2010 03:42:00 PM
    
    *       Revision:  none
    
    *       Compiler:  gcc
    
    *
    
    *         Author:  gnuhpc , warmbupt@gmail.com
    
    *        Company:  IBM CDL
    
    *
    
    * =====================================================================================
    
    */
    
    #include 
    
    #include 
    
    #include <string.h>
    
    #include 
    
    #include 
    
    #include 
    
    #define RUNNING_DIR	"/tmp"
    
    #define LOCK_FILE	"daemonexampled.lock"
    
    #define LOG_FILE	"daemonexampled.log"
    
    void log_message(char *filename,char *message)
    
    {
    
    	FILE *logfile;
    
    	logfile=fopen(filename,"a");
    
    	if(!logfile) 
    
    		return;
    
    	fprintf(logfile,"%s/n",message);
    
    	fclose(logfile);
    
    }
    
    void signal_handler(int sig)
    
    {
    
    	switch(sig) {
    
    	case SIGHUP:
    
    		log_message(LOG_FILE,"hangup signal catched");
    
    		break;
    
    	case SIGTERM:
    
    		log_message(LOG_FILE,"terminate signal catched");
    
    		exit(0);
    
    		break;
    
    	}
    
    }
    
    int main(void)
    
    {
    
    	int i,lfp;
    
    	char str[10];
    
    	if(getppid()==1) //Test if the process is running background
    
    		return 1; /* already a daemon */
    
    	
    
    	i=fork();
    
    	if (i<0) 
    
    		return 1; /* fork error */
    
    	if (i>0) 
    
    		return 0; /* parent exits */
    
    	
    
    	/* child (daemon) continues */
    
    	int sid = setsid(); /* obtain a new process group */
    
    	if( sid<0 )
    
    	{
    
    		exit 1;
    
    	}
    
    	for (i=getdtablesize();i>=0;--i) 
    
    		close(i); /* close all descriptors */
    
    	i=open("/dev/null",O_RDWR); 
    
    	dup(i); 
    
    	dup(i); /* handle standart I/O */
    
    	
    
    	umask(027); /* set newly created file permissions */
    
    	
    
    	chdir(RUNNING_DIR); /* change running directory */
    
    	
    
    	lfp=open(LOCK_FILE,O_RDWR|O_CREAT,0640);
    
    	if (lfp<0) 
    
    		return (1); /* can not open */
    
    	if (lockf(lfp,F_TLOCK,0)<0) 
    
    		return (1); /* can not lock */
    
    	/* first instance continues */
    
    	sprintf(str,"%d/n",getpid());
    
    	write(lfp,str,strlen(str)); /* record pid to lockfile */
    
    	
    
    	signal(SIGCHLD,SIG_IGN); /* ignore child */
    
    	signal(SIGTSTP,SIG_IGN); /* ignore tty signals */
    
    	signal(SIGHUP,signal_handler); /* catch hangup signal */
    
    	signal(SIGTERM,signal_handler); /* catch kill signal */
    
    	while( 1 )
    
    	{
    
    		/* do something here */
    
    		sleep(30);
    
    	}
    
    	return 0;
    
    }

    作者:gnuhpc
    出处:http://www.cnblogs.com/gnuhpc/


                   作者:gnuhpc
                   出处:http://www.cnblogs.com/gnuhpc/
                   除非另有声明,本网站采用知识共享“署名 2.5 中国大陆”许可协议授权。


    分享到:

  • 相关阅读:
    问题总结
    Https网络安全架构设计
    分布式ID生成策略
    [转]匿名内部类详解
    JAVA名词解释
    MQ实战
    手写SpringMVC实现
    多线程问答
    BIO、NIO实战
    spring中@Value("${key}")值原样输出${key}分析与解决
  • 原文地址:https://www.cnblogs.com/gnuhpc/p/2811919.html
Copyright © 2011-2022 走看看