当前位置: > Linux教程 > Linux学习 >

什么是 Linux守护进程

时间:2018-04-28 17:53来源:linux.it.net.cn 作者:IT

什么是守护进程

守护进程也称为精灵进程(Daemon),是运行在后台的一种特殊进程。它独立于控制终端并且周期性地执行某种任务或等待处理某些发生的事件。

例如Linux的大多数服务器就是用守护进程实现的。比如,ftp服务器,ssh服务器,Web服务器等。同时,守护进程完成许多系统任务。比如,作业规划进程crond等。

Linux系统启动时会启动很多系统服务进程,Windows系统也是如此,这些系统服务进程没有控制终端,不能直接和用户交互,当用户注销登陆后,这些进程还是会存在。所以守护进程一般来说自成进程组,自成会话,没有控制终端。

查看当前Linux系统下的部分守护进程

    命令: ps axj | more



- TPGID一栏为 -1 的都是没有控制终端的进程,也就是守护进程,而且SID一栏基本为0,相当于每个都是独立的会话,第一个为系统初始化进程。

- 在COMMAND一栏用[]括起来的名字表示内核线程,这些线程在内核里创建,没有用户空间代码,因此没有程序文件名和命令行,通常采用以K开头的名字,表示Kernel(操作系统内核)。
- 守护进程通常采用以d结尾的名字,表示Daemon。


创建守护进程

1. 创建子进程,终止父进程
守护进程是脱离与终端控制的,所以我们就要手动创建出一个僵尸进程,在形式上做到与控制终端脱离。因此先创建父进程,
fork一个子进程,然后父进程再子进程结束前退出,使得程序在shell终端里产生一个已经终止的假象所有的工作都在子进程中完成
2. 在子进程中创建新会话
这个步骤是创建守护进程中最重要的一步,在这里使用的是系统函数setsid。

因为子进程在fork之后,全盘拷贝了父进程的所有信息(包括进程组,会话期,控制终端等),而守护进程需要自成进程组,
自成会话,脱离控制终端。

所以我们就需要调用 setsid 函数,setsid函数用于创建一个新的会话,并担任该会话组的组长,调用setsid的三个作用:
让进程摆脱原会话期、原进程组和原控制终端的控制。
     #include <unistd.h>
     pid_t setsid(void);
     //该函数调用成功时返回新创建的 Session 的ID(其实也就是当前进程的ID),出错返回 -1 。
3. 改变工作目录
使用fork创建的子进程也继承了父进程的当前工作目录。由于在进程运行过程中,当前目录所在的文件系统不能卸载,
因此,把当前工作目录换成其他的路径,如“/”或“/tmp”等。改变工作目录的常见函数是chdir。
4. 重设文件创建掩码
文件创建掩码是指屏蔽掉文件创建时的对应位。由于使用fork函数新建的子进程继承了父进程的文件创建掩码,这就给该子进程
使用文件带来了诸多的麻烦。因此,把文件创建掩码设置为0,可以大大增强该守护进程的灵活性。设置文件创建掩码的函数umask
,通常的使用方法为umask(0)。
5. 关闭文件描述符
用fork新建的子进程会从父进程那里继承一些已经打开了的文件。这些被打开的文件可能永远不会被守护进程读或写,但它们一
样消耗系统资源,可能导致所在的文件系统无法卸载。

演示代码:
提醒大家以后写博客复制代码时要先把行号取消显示,Vim下是在末行模式下输入 :set nonu,显示行号是 :set nu
因为Markdown编辑器里的代码片会自动给你添加行号,你再把自己的复制上之后就会有两个行号,贼丑


 #include <stdio.h>                                                                                                                      
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdlib.h>
void  My_Daemon()
{
    umask(0);//调用umask将文件模式屏蔽字设置为0
    pid_t pid = fork();
    if(pid < 0)
    {   
        perror("fork");
        return;
    }else if(pid > 0)
    {   
    //2.父进程退出
        exit(0);
    }   
    //3.调用setsid创建一个新会话,使子进程脱离原进程组,会话期,控制终端
    setsid();
    //4.将当前工作目录改为根目录
    if(chdir("/") < 0)
    {   
        perror("chdir");
        return;
    }   
    //5.关闭文件描述符
    close(0);
}
int main()
{
    My_Daemon();
    while(1)
    {   
        sleep(1);
    }
    return 0;
}   

结果:

可以看到该进程已经变为守护进程了。我们也可以通过调用daemon函数直接将当前进程精灵化(听起来贼帅,对吧,而且用起来超简单)

       #include <unistd.h>
       int daemon(int nochdir, int noclose);
       //当 nochdir 为 0 时, daemon 将更改进程的根目录为 root 目录( / 目录)
       //当 noclose 为 0 时, daemon 将进程的 STDIN , SDTERR 都重定向到 /dev/null 。

#include <stdio.h>                                                                                                                      
#include <unistd.h>
int main()
{
    daemon(0,0);

    while(1);
}

当前进程变为守护进程




(责任编辑:IT)
------分隔线----------------------------