守护进程
(deamon)是一种特殊的进程,类似于windows下的服务,是一种在后台运行的服务进程,独立于控制终端,一般由系统启动时,引导启动,随着系统的关闭而关闭,不会随着用户的登录或者注销的影响。
守护进程的运行方式
①独立运行的守护进程:独立运行的守护进程由 init 脚本负责管理,所有独立运行的守护进程的脚本在/etc/rc.d/init.d/目录下。
②由 xinetd 管理的守护进程:可以把xinetd看作一个管理启动服务的管理服务器,它决定把一个客户请求交给那个程序处理,然后启动相应的守护程序。
创建守护进程
要想创建守护进程,我们需要先知道以下的概念。
- 进程组:进程组是一个或多个进程的集合,通常它们与一组作业相关联,可以接受来自同一终端的各种信号。每个进程组有一个领头进程,叫做进程组组长。pid_t getpgrp(void);该函数可以获取进程组的PID(即进程组组长的PID).int setpgid(pid_t pid, pid_t pgid);调用该函数该函数可以参加一个现存的组或者创建一个新进程组。需要注意的是,当父进程fork()出子进程的时候,系统会自动将子进程所在的进程组的组长设置为父进程。
- 会话:会话由多个进程组组成
创建会话的进程将会成为新进程组的组长
注意,创建会话的进程不能是进程组组长。pid_t getsid(pid_t pid);获取进程所属的会话ID。pid_t setsid(void);创建一个会话。
创建守护进程模型:
- fork()创建子进程,父进程退出。(子进程成为孤儿进程,不再由父进程控制子进程的生死)
- 子进程创建新会话。(成为会话组长,和进程组组长,脱离控制终端)
- 改变当前工作目录 chdir 。(建议步骤,为守护进程设置新的工作目录)
- 重设文件掩码 umask 。(建议步骤,增加程序的灵活性,守护进程和父进程将同同一文件,拥有不同的权限。umask(0)可以将所有权限给予守护进程。文件的最大权限为0777,其中umask的参数填写你要扣除的权限.0777即 (-rwxrwxrwx,文件拥有者的权限,同一用户组的权限,不同用户组的权限)r=4,w=2,x=1)
- 关闭文件描述符close(建议步骤,关闭从父进程那里继承来的文件描述符(标准输入,标准输出,标准错误))
- 守护进程的工作 sigaction捕捉信号(守护进程经常会使用信号进行通信,通过信号控制守护进程的退出,也可以使用signal,注意,signal并不是POSIX标准,机器不同,实现有可能不同)
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <string.h>
#include <sys/types.h>
#include <sys/time.h>
#include <time.h>
#include <fcntl.h>
#include <sys/stat.h>
void dowork(int no)
{
//得到当前系统时间
time_t curtime;
time(&curtime);
//格式化
char* pt = ctime(&curtime);
//将时间写入
int fd = open("/home/tarena/a.txt",O_CREAT | O_WRONLY | O_APPEND,0664);
write(fd,pt,strlen(pt)+1);
close(fd);
}
int main(int argc,char* argv[])
{
pid_t pid;
/*1.生成新进程,关闭父进程*/
pid=fork();
if(pid == 0)
{
/*2.子进程创建会话*/
setsid();
/*3.改变当前工作目录*/
chdir("/");
/*4.重设文件掩码*/
umask(0);
/*5.关闭文件描述符*/
close(STDIN_FILENO);
close(STDOUT_FILENO);
close(STDERR_FILENO);
/*6.守护进程工作,定时写入文件*/
//注册信号捕捉,signal
struct sigaction act;
//回调
act.sa_handler = dowork;
act.sa_flags = 0;
sigemptyset(&act.sa_mask);
sigaction(SIGALRM,&act,NULL);
//创建定时器
struct itimerval val;
//第一次触发时间
val.it_value.tv_usec = 0;
val.it_value.tv_sec = 2;
//循环周期
val.it_interval.tv_usec = 0;
val.it_interval.tv_sec = 1;
while(1)
{
/*定时器到时会发送SIGALRM*/
setitimer(ITIMER_REAL,&val,NULL);
}
}
else if (pid < 0)
{
perror("error is :");
return -1;
}
return 0;
}