守护进程

认识守护进程

守护护进程也称精灵进程(Daemon),是运⾏在后台的⼀种特殊进程。
独⽴于控制终端并且周期性地执⾏某种任务或等待处理某些发⽣的事件
Linux系统启动时会启动很多系统服务进程,这些系统服务进程没有控制终端,不能直接和⽤户交互。
其它进程都是在⽤户登录或运⾏程序时创建,在运⾏结束或⽤户注销时终⽌,但系统服务进程(守护进程)不受⽤户登录注销的影响,它们⼀直在运⾏着。这种进程有⼀个名称叫守护进程(Daemon)。 

守护进程是⼀种很有⽤的进程。
  • Linux的⼤多数服务器(因为一般服务器都需要 7*24 小时不间断运行)就是⽤守护进程实现的。⽐如,ftp服务器,ssh服务器,Web服务器httpd等。
  • 守护进程也完成许多系统任务。⽐如,作业规划进程crond等。

下⾯我们⽤ps axj命令查看系统中的进程。
  • 参数a表⽰不仅列当前⽤户的进程,也列出所有其他⽤ 户的进程
  • 参数x表⽰不仅列有控制终端的进程,也列出所有⽆控制终端的进程
  • 参数j表⽰列出与 作业控制相关的信息。

  • 凡是TPGID⼀栏写着-1的都是没有控制终端的进程,也就是守护进程。
  • 在COMMAND⼀列⽤[]括起来的名字表⽰内核线程,这些线程在内核⾥创建,没有⽤户空间代码,因此 没有程序⽂件名和命令⾏, 通常采⽤以k开头的名字,表⽰Kernel。

创建守护进程


我们可以在man 手册中查看守护进程如何创建(man 7 daemon)
  • SysV Daemons (man手册上分为15步,比较麻烦)
  • New-Style Daemons (新风格的守护进程,man手册上分为10步,也比较复杂)

一个比较简单的创建步骤(不过也没简单到哪里去...)
  1. 调用fork创建子进程,父进程终止,让子进程在后台继续执行.
  2. 子进程调用setsid创建一个新的会话,并失去控制终端,调用setsid()使子进程成为新的会话组组长和新的进程组组长,同时失去控制终端.
  3. 忽略 SIGHUP 信号,当关闭终端的时候,会话就会结束,会话结束进程组就会结束,进程组结束进程就会结束,SIGHUP信号就是负责向其他进程组发送该信号,造成其他进程终止.
  4. 忽略 SIGCHLD 信号,避免后面创建的子进程产生僵尸进程.
  5. 再次调用fork创建子子进程,子进程终止,子子进程继续执行,由于子子进程不在是会话组的组长,从而禁止进程重新打开终端(这一步不是必须的).
  6. 吧当前的工作目录改成根目录,一般将工作目录改到根目录,这样进程的启动目录也可以被卸掉.
  7. 关闭打开的文件描述符,打开一个空设备,并复制到标准输出和标准错误上.避免调用一些库函数依然向屏幕输出信息.
  8. 重设文件创建掩码清除从父进程那里继承来的文件掩码,设为0

代码如下:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <fcntl.h>
#include <sys/stat.h>

void MyDaemon()
{
    // 1.创建子进程,子进程继续执行,父进程终止
    pid_t pid = fork();
    if(pid < 0)
    {
        perror("fork");
        return;
    }
    if(pid > 0)
    {
        exit(0);
    }
    // 2.子进程调用 setsid
    setsid();
    // 3.忽略 SIGHUP信号
    signal(SIGHUP,SIG_IGN);
    // 4.忽略 SIGCHLD信号
    signal(SIGCHLD,SIG_IGN);
    // 5.修改工作目录为根目录
    chdir("/");
    // 6.重定向文件描述符
    int fd = open("/dev/null",O_RDWR); //类似于垃圾桶的文件,写入的数据直接丢弃
    if(fd < 0)
    {
        perror("fd");
        exit(1);
    }
    dup2(fd,1);
    dup2(fd,2);
    // 7.修改 umask
    umask(0);
}

int main()
{
    MyDaemon();
    while(1)
    {
        sleep(1);
    }
    return 0;
}
我么一执行,发现当前并不是一个前台进程
通过ps指令查看

当前TPGID这一行已经变成了 -1,证明现在的进程是守护进程.

我们可以关闭当前的终端,重启一个终端,再次查看,mydaemon这个守护进程依旧存在.

daemon函数

上面的步骤太太太繁琐了,C语言为我们提供了一个daemon函数

#include <unistd.h>
int daemon(int nochdir, int noclose);

两个参数(man 3 daemon):
    If nochdir is zero, daemon() changes the calling process's current working directory to the root  directory  ("/");  other‐wise, the current working directory is left unchanged.

    If  noclose  is  zero,  daemon()  redirects  standard input, standard output and standard error to /dev/null; otherwise, nochanges are made to these file descriptors.

代码演示:
#include <stdio.h>
#include <unistd.h>

int main()
{
    daemon(0,0);
    while(1)
    {
        sleep(1);
    }
    return 0;
}
nohup指令

可以直接将一个进程变为守护进程. 及其好用!!!

使用:
    nohup [要变为守护进程的进程] &

我们发现当前的TPGID并不是-1,不要紧,我们重启终端,再来查看

当前的 TPGID 就是-1 了
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值