您的位置:首页 > 编程语言 > C语言/C++

UNIX环境C语言编程(10)-守护进程

2015-02-04 17:22 302 查看
1、守护进程的特征

•英文名称daemon,又称为常驻进程、精灵进程
•守护进程有以下特征:
•1、长时间后台运行,通常随系统启停而启停
•2、大多系统守护进程具有root权限
•3、没有控制终端
•4、所有用户级别(非内核级别)的守护进程都是进程组长、会话领导,
        并且是进程组与会话中的唯一一组进程

•5、大多守护进程的父进程都是init进程
 

2、编码规则

•如果编码实现一个守护进程,需要考虑哪些因素:
•1、将文件创建掩码umask设置为0
•2、调用fork,然后父进程退出,目的:
        shell能够接收下一条指令;

        子进程不是进程组长,这是调用setsid函数的先决条件

•3、调用setsid创建一个新的会话
        当前进程成为新会话的领导、成为新进程组的组长、没有控制终端

•4、将当前工作目录改变为根目录/
•5、关闭不再需要的文件描述符
•6、一些daemon进程将描述符0、1、2重定向为/dev/null设备
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>

void z_daemon(void)
{
pid_t  childpid = 0;
struct sigaction sa;

sigemptyset(&sa.sa_mask);
sa.sa_flags = 0;

/* 忽略信号 */
sa.sa_handler = SIG_IGN;
sigaction(SIGQUIT, &sa, NULL);
sigaction(SIGHUP,  &sa, NULL);
sigaction(SIGINT,  &sa, NULL);
sigaction(SIGPIPE, &sa, NULL);

#ifdef SA_NOCLDSTOP
sa.sa_flags |= SA_NOCLDSTOP;
#endif
#ifdef SA_NOCLDWAIT
sa.sa_flags |= SA_NOCLDWAIT;
#endif

sigaction(SIGCHLD, &sa, NULL);

if( getppid() == 1 ) return;

fflush(stdout); fflush(stderr);

umask(0);

childpid = fork();
if( childpid < 0 ) exit(0);
else if( childpid > 0 ) exit(0);

/*  the first child process  */
if( setsid() == (pid_t) (-1) ) exit(0);

childpid = fork();
if( childpid < 0 ) exit(0);
else if( childpid > 0 ) exit(0);

/*  the second child process */
return;
}


3、单实例守护进程

•即只能启动一个实例,不能多个实例同时运行
•如果做到这一点?
•文件与记录锁机制提供了一种简便的互斥机制
•一个进程放置“写”锁后,其它进程后续的加锁尝试都会失败
•另外,进程退出后,文件锁会自动释放,免除了手工清理的麻烦
•文件锁机制在下一章节详述,一个简单示例:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/stat.h>

#define LOCKFILE "daemon.pid"
#define LOCKMODE (S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)

int already_running(void)
{
int     fd;
char    buf[16];

fd = open(LOCKFILE, O_RDWR|O_CREAT, LOCKMODE);
if( fd < 0 )
{
printf("can't open %s: %s\n", LOCKFILE, strerror(errno));
exit(1);
}
if( lockf(fd, F_TLOCK, 0) < 0 )
{
if( errno == EACCES || errno == EAGAIN )
{
close(fd);
return(1);
}
printf("can't lock %s: %s\n", LOCKFILE, strerror(errno));
exit(1);
}

ftruncate(fd, 0);
sprintf(buf, "%ld", (long)getpid());
write(fd, buf, strlen(buf) + 1);

return(0);
}

int main(void)
{
if( already_running() )
{
printf("already running ...\n");
exit(0);
}

printf("ok\n");
sleep(100);
}


4、守护进程的惯例

•系统的守护进程在收到SIGHUP信号后,会重新读取配置文件
 
5、客户机/服务器模型

•守护进程通常充当一个服务器,等待客户端请求,并处理
•后续章节会看到更多的双向通信的示例:
•客户端发送请求,服务器处理并且,并发送响应结果
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息