【Linux】如何创建daemon进程&fork一次和fork两次有什么区别

前言


本文适合对Linux进程有了解过的读者。Linux中有一种进程叫做守护进程,又称精灵进程。它运行在后台,很重要,Linux下大多数服务器就是用守护进程实现的。因为它独立于终端运行,也就是说它的运行不受当前登录或者注销的影响,自成会话,周期性的执行某项任务或者等待处理某些事件。其他进程则是在登录或者运行时创建,在运行结束或者注销用户时终止。守护进程命名通常以d结尾,父进程是1号进程,它其实是属于孤儿进程,因为我们知道1号进程会领养所有无父进程的孤儿进程。

创建守护进程


创建守护进程可以分为如下几步:
1. umask设置为0。
2. 调用fork函数,再将父进程退出。
3. 调用setsid函数创建⼀个新的Session,并成为Session Leader。
4. 改变当前目录为根目录
5. 关闭文件描述符
6. 忽略SIGCHLD信号(子进程退出时会发给父进程的信号)

调用setsid函数之前,当前进程不允许是进程组的Leader,否则该函数返回-1。这就是fork后将父进程退出的原因。毕竟刚创建出来的子进程不会是进程组组长。

setsid函数的作用:
1)子进程成为新会话的⾸进程。
2)子进程成为⼀个进程组的组长进程 。
3)子进程没有控制终端。

#include.h>
#include.h>
#include.h>
#include.h>
int main()
{
    umask(0);
    if(fork()>0)
    {
        exit(0);    //父进程退出
    }
    setsid();     //设置新会话
    chdir("/");   //更改当前工作目录为根目录
    close(0);    //关闭标准输入流
    close(1);     //关闭标准输出流
    close(2);    //关闭标准错误流
    signal(SIGCHLD,SIG_IGN);   //忽略SIGCHLD信号
    while(1)
    {
        sleep(1);
    }
    return 0;
}

可以看到,上面的代码中fork了一次就完成了对守护进程的创建。那为什么有人创建时需要fork两次呢?一次和两次的作用是不同的,如下:
调用第一次fork的作用
让shell认为这条命令已经终止,不用挂在终端输入上;为后面setsid服务,因为调用setsid函数的进程不能是进程组组长,如果不fork出子进程,则此时的父进程是进程组组长,就无法调用setsid。当子进程调用完setsid函数之后,子进程是会话组长也是进程组组长,并且脱离了控制终端,此时,不管控制终端如何操作,新的进程都不会收到一些信号使得进程退出。
第二次fork的作用
虽然当前关闭了和终端的联系,但是后期可能会误操作打开了终端。
但是只有会话首进程能打开终端设备,所以再fork一次,把父进程退出,再次fork的子进程作为守护进程继续运行,保证了该精灵进程不是对话期的首进程,第二次不是必须的,是可选的。

总结


守护进程是Linux中重要的角色,它无控制终端,自成会话,生存周期与用户登录注销无关,常用于常驻内存的网络服务。Linux提供了一个函数可以直接创建守护进程。

int daemon(int nochdir, int noclose);

使用时两个参数都传0即可,代表当前工作目录变更为根目录;关闭文件描述符。相当于文件描述符重定向到 /dev/null,写入到这里的内容会被操作系统丢弃。

你可能感兴趣的:(Linux,linux,守护进程)