美文网首页
进程守护进程

进程守护进程

作者: wayyyy | 来源:发表于2021-04-01 23:56 被阅读0次

什么是守护进程?
Linux 的大多数服务器就是用守护进程实现的,使用ps -axj可以查看守护进程:

image.png
  • 守护进程基本上都是以超级用户启动( UID 为 0 )
  • 没有控制终端( TTY 为 ?)
  • 终端进程组 ID 为 -1 ( TPGID 表示终端进程组 ID)

如何编写守护进程?

设置umask

Linux 不同,它是通过使用 umask 默认权限来给所有新建的文件和目录赋予初始权限的。

# umask  # root用户默认是0022,普通用户默认是 0002
  0022

这里先调用umask将文件模式创建屏蔽之设置为一个已知的值,通常是0。

umask(0);
在后台运行
//1)在父进程中,fork返回新创建子进程的进程ID;
//2)在子进程中,fork返回0;
//3)如果出现错误,fork返回一个负值;
int pid = fork();
if (pid < 0)
{
    std::cout << "fork error" << std::endl;
    exit(-1);
}
//父进程退出,子进程独立运行
else if (pid > 0) 
{
    exit(0);
}

调用fork,然后使父进程exit,这样做的目的是:
1、如果该进程是作为一条简单的 shell 命令启动的,那么父进程终止会让 shell 认为这条命令已经执行完毕。
2、虽然子进程继承了父进程的进程组ID,但获得了一个新的进程ID,这样就保证了 子进程不是一个进程组的组长进程,这是下面将要进行的setsid调用的先决条件。

脱离控制终端,登录会话和进程组
setsid();
signal(SIG_HUP, SIG_IGN);
if ((pid = fork()) < 0)
{
    std::cout << "fork error" << std::endl;
    exit(-1);
}
else if (pid != 0)
{
    exit(0);
}

关于setsid()

pid_t setsid();    // 成功返回进程组ID,出错返回-1
image.png

如果调用此函数的进程不是一个进程组的组长,则此函数创建一个新会话,具体会发生下列3件事:
1、该进程变成新会话的会话首进程
2、成为一个新进程组的组长进程,组ID就是该调用进程的ID
3、该进程没有控制终端

如果该调用进程已经是一个进程组的组长进程,则函数返回出错,为了便面这种情况,通常先调用fork,然后使其父进程终止,子进程继续。

改变当前的工作目录

更改工作目录,从父进程继承过来的当前工作目录可能在 一个挂载的文件系统中,如果守护进程的当前目录挂载在一个文件系统中,那么该文件系统就不能被卸载。

chdir("/");
关闭打开的文件描述符
int fd = open("/dev/null", O_RDWR, 0);
if (fd != -1)
{
    dup2(fd, STDIN_FILENO);
    dup2(fd, STDOUT_FILENO);
    dup2(fd, STDERR_FILENO);
}
if (fd > 2)
{
    close(fd);
}
处理 SIGCHLD 信号
signal(SIGCHLD, SIG_IGN);
完整实现
#include <iostream>
#include <sys/types.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <signal.h>

void daemon_run()
{
    pid_t pid = fork();
    if (pid < 0)
    {
        std::cout << "fork error" << std::endl;
        exit(-1);
    }
    else if (pid > 0)
    {
        exit(0);
    }

    pid_t group = setsid();
    if (group < 0)
    {
        std::cout << "setsid error" << std::endl;
        exit(-1);
    }

    if ((pid = fork()) < 0)
    {
        std::cout << "fork error" << std::endl;
        exit(-1);
    }
    else if (pid != 0)
    {
        exit(0);
    }

    int fd = open("/dev/null", O_RDWR, 0);
    if (fd != -1)
    {
        dup2(fd, STDIN_FILENO);
        dup2(fd, STDOUT_FILENO);
        dup2(fd, STDERR_FILENO);
    }
    if (fd > 2)
    {
        close(fd);
    }

    signal(SIGHUP, SIG_IGN);
    signal(SIGCHLD, SIG_IGN);
}

int main(int argc, char **argv)
{
    int ch;
    bool b_daemon = false;
    while ((ch = getopt(argc, argv, "d")) != -1)
    {
        switch (ch)
        {
        case 'd':
            b_daemon = true;
            break;
        }
    }

    if (b_daemon)
    {
        daemon_run();
    }

    while (1)
    {
    }
}

参考资料
1、《UNIX环境高级编程》
2、https://blog.csdn.net/lianghe_work/article/details/47659889

相关文章

  • rsync服务企业应用

    守护进程服务企业应用: 守护进程多模块功能配置 守护进程的排除功能实践 守护进程来创建备份目录 守护进程的访问控制...

  • Python多进程

    守护进程 守护进程其实就是“子进程“是否伴随主进程一起结束:守护==>伴随,即守护进程会伴随主进程的代码运行完毕后...

  • 守护进程和守护线程详解

    守护进程 什么是守护进程? 守护进程会在主进程代码运行结束的情况下,立即挂掉。 守护进程本身就是一个子进程。 主进...

  • 4.5、守护进程及信号处理实战

    1、守护进程功能的实现守护进程融入项目,解放终端。相关配置:Daemon = 1;按照守护进程的方式运行守护进程如...

  • PHP创建守护进程

    PHP 创建守护进程 执行守护进程

  • forever

    start:启动守护进程stop:停止守护进程stopall:停止所有的forever进程restart:重启守护...

  • 守护进程,互斥锁,队列,生产者消费者模型

    守护进程 关于守护进程需要强调两点: 其一:守护进程会在主进程代码执行结束后就终止 其二:守护进程内无法再开启子进...

  • 进程守护进程

    什么是守护进程?Linux 的大多数服务器就是用守护进程实现的,使用ps -axj可以查看守护进程: 守护进程基本...

  • redis.conf详解之daemonize

    用法 作为非守护进程运行 作为守护进程运行 注意事项: 默认情况下,Redis不作为守护进程运行。如果以守护进程运...

  • 开源HIDS-Wauzh功能测试

    一、Wazuh 守护进程及工具进程 守护进程 ossec-agentd https://documentation...

网友评论

      本文标题:进程守护进程

      本文链接:https://www.haomeiwen.com/subject/ergjzktx.html