进程中的守护进程

守护进程

守护进程的特点

后台服务进程

独立于控制终端

周期性执行某任务

不受用户登录注销影响

一般采用以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、执行核心工作------》必须的

测试

创建一个守护进程, 每隔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;
}

测试结果

在这里插入图片描述

在这里插入图片描述

关键代码分析

1、父进程死掉,子进程通过setsid成为会话组的组长,也就开始成为一个守护进程。

2、设置定时器每个2s捕捉信号SIGALRM,通过时间转换函数将时间转化为人可以识别的时间。

猜你喜欢

转载自blog.csdn.net/zxy131072/article/details/89631302