Linux系统编程——守护进程(1)

举报
xcc-2022 发表于 2022/10/24 20:52:18 2022/10/24
【摘要】 05. 守护进程(重点) 5.1 守护进程介绍守护进程(Daemon Process),也就是通常说的 Daemon 进程(精灵进程),是 Linux 中的后台服务进程。它是一个生存期较长的进程,通常独立于控制终端并且周期性地执行某种任务或等待处理某些发生的事件。一般采用以d结尾的名字。守护进程是个特殊的孤儿进程,这种进程脱离终端,为什么要脱离终端呢?之所以脱离于终端是为了避免进程被任何终...

05. 守护进程(重点)

5.1 守护进程介绍

守护进程(Daemon Process),也就是通常说的 Daemon 进程(精灵进程),是 Linux 中的后台服务进程。它是一个生存期较长的进程,通常独立于控制终端并且周期性地执行某种任务或等待处理某些发生的事件。一般采用以d结尾的名字。

守护进程是个特殊的孤儿进程,这种进程脱离终端,为什么要脱离终端呢?之所以脱离于终端是为了避免进程被任何终端所产生的信息所打断,其在执行过程中的信息也不在任何终端上显示。由于在 Linux 中,每一个系统与用户进行交流的界面称为终端,每一个从此终端开始运行的进程都会依附于这个终端,这个终端就称为这些进程的控制终端,当控制终端被关闭时,相应的进程都会自动关闭。

Linux 的大多数服务器就是用守护进程实现的。比如,Internet 服务器 inetd,Web 服务器 httpd 等。

5.2 守护进程模型

  1. 创建子进程,父进程退出(必须)
  • 所有工作在子进程中进行形式上脱离了控制终端
  1. 在子进程中创建新会话(必须)
  • setsid()函数
  • 使子进程完全独立出来,脱离控制
  1. 改变当前目录为根目录(不是必须)
  • chdir()函数
  • 防止占用可卸载的文件系统
  • 也可以换成其它路径
  1. 重设文件权限掩码(不是必须)
  • umask()函数
  • 防止继承的文件创建屏蔽字拒绝某些权限
  • 增加守护进程灵活性
  1. 关闭文件描述符(不是必须)
  • 继承的打开文件不会用到,浪费系统资源,无法卸载
  1. 开始执行守护进程核心工作(必须)

守护进程退出处理程序模型

5.3 守护进程参考代码1

写一个守护进程, 每隔2s获取一次系统时间, 将这个时间写入到磁盘文件:

/*
* 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/edu/timelog.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("/home/edu");

        // 更改掩码
        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 = 2;
        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;
}

image-20220926141611700

5.4 守护进程参考代码2

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<unistd.h>

//守护进程模型
int main()
{
    pid_t pid = -1;

    //1.创建子进程,父进程退出
    pid = fork();
    if(-1 == pid)
    {
        perror("fork");
        return 1;
    }
    if(pid > 0)
    {
        //父进程退出
        exit(0);
    }

    //2.在子进程中创建新会话,完全脱离工作目录
    pid = setsid();
    if(-1 == pid)
    {
        perror("setsid");
        return 1;
    }
    //3.改变当前目录为根目录
    pid = chdir("/");
    if(-1 == pid)
    {
        perror("chdir");
        return 1;
    }
    //4.重设文件权限掩码
    umask(0);
    //5.关闭文件描述符
    close(STDIN_FILENO);//stdin--->FILE *
    close(STDOUT_FILENO);
    close(STDERR_FILENO);

    //6.开始执行守护进程核心工作
    //每隔两秒钟输出当前的时间到/tmp/txt.log文件中
    while(1)
    {
        system("date >> /tmp/txt.log");
        sleep(2);
    }
    return 0;
}

预览:

动画8

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。