关于linux:请收下这个在linux创建守护进程的工具附源码

43次阅读

共计 2294 个字符,预计需要花费 6 分钟才能阅读完成。

先给工具
源码和工具都在这里自取
https://github.com/tangbu/myblob/tree/master/c/deamon
这是一个 c 编译而成的可运行程序,名字叫 deamon,比方本来执行 /bin/test -Darg1=value1, 当初执行 deamon /bin/test -Darg1=value1 就能够
原理浅显易懂,java 程序员不影响浏览

产生了什么事件

笔者的电脑操作系统为 ubuntu,数年以前在兴高采烈的关上 postman 的时候调试,忽然想整顿多余的 bash 命令界面,忽然正在工作的 postman 退出了工作,留下我默默发愣。通过测试,应用 postman 的时候必须放弃 bash 界面关上状态,也就是我要始终面对这个黑黑的窗口无奈关掉

寻找解决办法

解决办法 1 nohup,

网上搜寻 nohup 能够让过程在后盾运行,会在当前目录下生成 nohup.out, 输入会重定向增加到 nohup.out 外面去,然而并不胜利

解决办法 2 & 符号和 -d

命令前面加 & 符号和 -d,postman -d &, 也不胜利页面卡死

解决办法 3 disown

应用 disown 命令,执行 postman 的时候界面不给输出命令的机会,导致无奈执行 disown 命令

postman 退出起因

执行 man bash 命令看一下为什么会导致 postman 退出

shell 退出的时候会向 shell 启动的 jobs 发送 SIGHUP 信号,过程在接管到 SIGHUP 的时候,如果过程没有向操作系统注册信号处理函数的时候 ProcessId,操作系统就会敞开该过程

守护过程

守护过程 在 linux 操作系统中, 守护过程 (deamon) 是作为后盾过程运行的过程,对于在 bash 启动的工作(job), 如果间接退出 job 同样会失落。为了解决这个问题,须要应用守护过程的形式启动工作。

接下来咱们看一下如何把命令行运行的程序编程守护过程

守护过程的创立

依然以命令行间接运行 postman 为例,执行命令查看过程树结构

ps -ajx | egrep 'postman|bash|PPID'

能够看到,终端过程和 postman 命令过程在同一会话 ID 中,postman 的父过程为终端。

从终端创立一个过程 A,A 过程再 fork 一个子过程 B 执行 postman 命令, 而后 A 过程退出

这样就能够创立运行 postman 命令的过程,实质上和间接在终端运行 postman 命令过程成果一样,然而咱们能够通过 c 代码对 B 过程属性更改让最终的过程继承更改后的个性

在子过程中创立新会话

从终端创立一个过程 A,A 过程再 fork 一个子过程 B,这时候,子过程的 SID 会话 id 和终端依然是一个,当终端退出的时候,依然会发送 SIGHUP 信号,子过程默认依然会退出,所以子过程 B 依然须要新建一个会话,就用到了上面的函数
setsid() 函数
使子过程齐全独立进去,脱离终端管制,能够 man 3 setsid 看一下应用

扭转当前目录为根目录

chidr()函数
避免工作在可卸载的文件系统,文件系统的卸载后,过程也随之沦亡,所以个别更改到根目录下

重设文件权限掩码

umask()函数

本机的 umask 的是 0002 第一个 0 不思考
所以在代码中创立 777,002 代表写,这个 umask 创立的文件默认去掉写权限(位运算)775, 防止影响到守护过程
umask(0);

敞开文件描述符

重定向 dup2()
规范输入输出、谬误都给丢掉。而后把继承下来的关上的文件描述符关掉,防止占用资源

理论运行的源码

上面是附正文的 C 代码


#include <unistd.h>
#include <signal.h>
#include <string.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <fcntl.h>


int main(int argc,  char* argv[])
{
    //pid_t int 类型, a 代表子过程号
    pid_t a;
    // 创立子过程,父过程中 a 是子过程号,子过程中 a =0
    a = fork();
    if(a > 0)
    {
        // 父过程退出,子过程继承父过程代码块持续运行,a 就是子过程号
        exit(0);
    }
//    子过程疏忽终端退出 SIGHUP 信号
    signal(SIGHUP, SIG_IGN);
    
//    创立新会话,脱离原会话,脱离管制终端。setsid();
    // 脱离原过程组,创立并进入只蕴含本身的过程组
    setpgrp();
    
    // 敞开父辈继承下来的所有文件
    int max_fd = sysconf(_SC_OPEN_MAX);
    for (int i = 0; i < max_fd && i > 2; i++) 
    {close(i);
    }

    // 设置掩码位
    umask(0);

    int drop_fd=open("/dev/null", O_RDWR);
    dup2(0, drop_fd);
    dup2(1, drop_fd);
    dup2(2, drop_fd);

    // 切换工作门路
    chdir("/");

// deamon postman arg1 args 变成了 postman arg1 arg2

    if (argc > 2) {char *params[argc - 2];
        memcpy(params, argv + 1, sizeof params);
        params[argc - 3] = NULL;
// execvp 反对在环境变量 PATH 中寻找 postman 命令并替换代码段,运行新过程的代码段,execvp(*params, params);
    } else {execvp(argv[1], NULL);

    }
    return 0;
}

接下来执行 deamon postman 命令查看过程关系

能够看到 postman 的父过程曾经变成了 systemd,比拟新的零碎守护过程曾经由 systemd 接管,咱们的守护过程创立胜利

正文完
 0