您现在的位置是:首页 >技术杂谈 >Linux守护进程(Daemon Process)网站首页技术杂谈

Linux守护进程(Daemon Process)

嘻嘻物质 2023-06-28 09:19:01
简介Linux守护进程(Daemon Process)

1. 守护进程概念:

        独立于终端控制并周期性地执行某些任务的后台进程。


2. 守护进程创建步骤:

核心:让进程脱离控制终端→创建新会话。

(1)创建子进程,父进程退出(必须);

        a) 所有工作在子进程中进行,形式上脱离控制终端(不占用终端),但用ps命令查看仍显示属于终端;

(2)子进程创建新会话(必须);

(创建新会话的核心目的是为了让守护进程在后台独立运行、脱离原先属于某个终端的进程组、会话,不受任何终端或信号的干扰,也不影响其他进程或会话)

        a)setsid函数;

        b)子进程完全独立,脱离终端控制;

        c)子进程成为新会话的领导进程,拥有自己的进程组和会话ID;

(3)再次创建子进程,第一个子进(会长进程)程退出(非必须);

(最好加入此步骤,因为步骤1的子进程是会长进程,有能力重新打开终端,其他进程不能。会长、组长进程退出了,此会话变成了无会长的会话,但不影响其中的其他进程的运行,反而使得守护进程更独立、安全)

        a)fork函数;

        b)防止第一个子进程重新打开控制终端,因为它是会话的领导进程;

(4)将工作目录改为根目录(非必须);

        a)chdir函数;

        b)防止当前工作目录是可卸载的文件系统;

(5)重设文件权限掩码(非必须);

(守护进程从父进程继承了文件权限掩码,可能会导致守护进程创建的文件或目录的权限不符合预期,例如缺少某些必要的读、写或执行权限。为避免该问题,守护进程可调用umask(0)函数来清除文件权限掩码,这样就可以根据需要来设置文件或目录的权限。)

        a)umask函数;

        b)防止继承的文件创建屏蔽子拒绝某些权限;

(6)关闭文件描述符(非必须);

        a)继承的打开文件用不到,占用资源,无法卸载;

        b)关闭标准输入、输出和错误输出,或者重定向到/dev/null或其他地方,避免输出到控制终端或影响其他程序;

(7)执行守护进程的任务(必须);

        a)使用循环、定时器、信号等机制来周期性地或事件驱动地执行任务;

        b)使用syslog或其他方式记录错误信息或日志信息,方便调试和监控;

        c)处理可能出现的异常,如资源耗尽、死锁、崩溃等。


3. 守护进程示例:

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

int main(int argc, const char* argv[]) {

    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 = fork();
    if (-1 == pid) {
        perror("fork");
        return 1;
    }

    if (pid > 0) {
        exit(0);
    }

    // 4.改变工作目录
    if (chdir("/") < 0) {
        perror("");
        return 1;
    }

    // 5.设置权限掩码
    umask(0);

    // 6.关闭文件描述符
    close(STDIN_FILENO);
    close(STDOUT_FILENO);
    close(STDERR_FILENO);

    // 7.执行核心任务
    while (1) {
        /*核心任务*/
        sleep(1);
    }

    return 0;
}

运行结果:

注意:第一个a.out是创建成功的守护进程,隶属终端已经变成 “ ? ” ,表示不属于任何终端;

           第二个a.out是grep命令查看内容的高亮显示而已。

风语者!平时喜欢研究各种技术,目前在从事后端开发工作,热爱生活、热爱工作。