守护进程的特点
后台服务进程
独立于控制终端
周期性执行某任务
不受用户登录注销影响
一般采用以d结尾的名字(服务)
进程组
进程的组长:组里边的第一进程
进程组的ID == 进程组的组长的ID
进程组组长的选则:进程中的第一个进程
进程组ID的设定:进程组的id就是组长的进程ID
会话:多个进程组
创建一个会话注意事项
1、不能是进程组长
2、创建会话的进程成为新进程组的组长
3、创建出的新会话会丢弃原有的控制终端
一般步骤先fork, 父亲死, 儿子执行创建会话操作(setsid)
获取进程所属的会话ID
pid_t getsid(pid_t pid);
创建一个会话
pid_t setsid(void);
创建守护进程模型
1、fork子进程,父进程退出-----》必须
2、子进程创建新会话-----------》必须
setsid();
3、改变当前工作目录chdir
插了一个U盘,a.out, 在U盘目录中启动a.out
a.out启动过程中,U盘拔掉了,不是必须的。
4、重设文件掩码
子进程会继承父进程的掩码,增加子进程程序操作的灵活性。
umask(0);不是必须的
5、关闭文件描述符
close(0);
close(1);
close(2);
释放资源,不是必须的
6、执行核心工作------》必须的
框架如下
#include <stdio.h>
#include <unistd.h>
int main(int argc, char const *argv[])
{
int i;
pid_t pid ;
pid = fork();
if(0 > pid)
{
perror("fork");
return -1;
}
else if(0 < pid)
{
_exit(0);
}
setsid();
chdir("/");
umask(0);
for(i = 0; i < getdtablesize() ; i++)
{
close(i);
}
while(1);
return 0;
}
测试
创建一个守护进程, 每隔2s获取一次系统时间, 将这个时间写入到磁盘文件。
测试源码
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
#include <signal.h>
#include <sys/time.h>
#include <time.h>
#include <fcntl.h>
/*
* time_t rawtime;
* time ( &rawtime ); --- 获取时间,以秒计,从1970年1月一日起算,存于rawtime
* localtime ( &rawtime ); //转为当地时间,tm 时间结构
* asctime() // 转为标准ASCII时间格式:
*/
void write_time(int num)
{
time_t rawtime;
struct tm * timeinfo;
// 获取时间
time(&rawtime);
#if 0
// 转为本地时间
timeinfo = localtime(&rawtime);
// 转为标准ASCII时间格式
char *cur = asctime(timeinfo);
#else
char* cur = ctime(&rawtime);
#endif
// 将得到的时间写入文件中
int fd = open("/home/mint/log.txt", O_RDWR | O_CREAT | O_APPEND, 0664);
if(fd == -1)
{
perror("open error");
exit(1);
}
// 写文件
int ret = write(fd, cur, strlen(cur)+1);
if(ret == -1)
{
perror("write error");
exit(1);
}
// 关闭文件
close(fd);
}
int main(int argc, const char* argv[])
{
pid_t pid = fork();
if(pid == -1)
{
perror("fork error");
exit(1);
}
if(pid > 0)
{
// 父进程退出
exit(1);
}
else if(pid == 0)
{
// 子进程
// 提升为会长,同时也是新进程组的组长
setsid();
// 更改进程的执行目录
chdir("/");
// 更改掩码
umask(0022);
// 关闭文件描述符
close(STDIN_FILENO);
close(STDOUT_FILENO);
close(STDERR_FILENO);
// 注册信号捕捉函数
// ×××××××××××××××× 先注册,再定时 ×××××××××××××××××××××××××××
struct sigaction sigact;
sigact.sa_flags = 0;
sigemptyset(&sigact.sa_mask);
sigact.sa_handler = write_time;
sigaction(SIGALRM, &sigact, NULL);
// 设置定时器
struct itimerval act;
// 定时周期
act.it_interval.tv_sec = 1;
act.it_interval.tv_usec = 0;
// 设置第一次触发定时器时间
act.it_value.tv_sec = 2;
act.it_value.tv_usec = 0;
// 开始计时
setitimer(ITIMER_REAL, &act, NULL);
// 防止子进程退出
while(1);
}
return 0;
}