守护进程(精灵进程)

什么是守护进程

守护进程也称精灵进程(Daemon),是运行在后台的一种特殊进程。它独立于控制终端并且周期性的执行某种任务或等待处理某些发送的事件。Linux上的大多数服务器就是用守护进程实现的。
这里写图片描述
我们可以看到在系统启动默认的守护进程,他们的父进程ID全是init;比如:我们比较熟悉的sshd,远程连接的守护进程;我在前面的写道的crond就是作业规划进程;

Linux系统启动时会启动很多系统服务进程,这些系统服务进程没有控制终端,不能直接和用户交互。其他进程启东市都是在用户登录或运行程序是创建,在运行结束或用户注销时终止,但系统服务进程不受用户登录注销影响,他们一直运行着。这种进程就叫做守护进程(精灵进程)(Deamon)
守护进程有个特征就是在程序运行名后面多了一个d;但是不是所有的尾字母是d的就是守护进程;

如何创建一个守护进程

在创建一个守护进程的最关键的步骤是调用setsid函数双肩一个新的会话,并成为会话组长;

#include<unistd.h>
pid_t setsid(void);

该函数调用成功,返回新创建的会话ID,出错返回-1;调用这个函数之前,当前进程不允许是进程组的组长,否则就出错;所以我们在调用setsid()函数之前,必须先fork()创建父子进程,父子进程在同一个进程组中,父进程是组长进程,所以子进程符合条件,将父进程退出即可满足要求;
成功调用该函数的结果是:

1、创建一个新的会话,当前进程成为会话组长,当前进程的id就是会话id;
2、创建一个新的进程组,当前进程成为进程组的组长,当前进程的ID就是进程组的ID;
3、如果当前进程原本有一个控制终端,则它失去这个控制终端,成为一个没有控制终端的进程。所谓失去控制终端是指,原来的控制终端仍然打开,仍然可以读写,但只是一个普通的打开文件额不是控制终端了。
创建守护进程的步骤
1、调用umask()将文件模式创建屏蔽字设置为0;
2、调用fork,父进程退出。//1、保证守护进程不是进程组长
3、调用setsid创建一个会话。//setsid会导致:1、调用进程成为新会话的首进程,2、调用进程成为一个进程组的组长进程,3、调用进程没有控制终端。
4、将当前工作目录更改我根目录。//系统中除了跟目录都可以被删除
5、关闭不在需要的文件描述符
6、忽略SIGCHLD信号;

自己创建守护进程:

#include<stdio.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<signal.h>
#include<unistd.h>
#include<stdlib.h>


void mydaemon()                 //只fork()一次
{
    umask(0);                   //用umask将文件模式创建为屏蔽字为0
    if(fork() == 0)             //fork子进程,关闭父进程
    {}
    else
    {
        exit(0);
    }
    setsid();                   //让子进程成为一个守护进程
    chdir("/");                 //更改当前目录为根目录
    close(0);                   //关闭默认的文件描述符表
    close(1);
    close(2);
    signal(SIGCHLD, SIG_DFL);   //忽略SIGCHLD信号
}
int main()
{

    mydaemon();
//  daemon(0, 0);                //系统自己定义的守护进程,没有关闭它的默认的文件描述符表,两个参数(默认更改路径到'/', 不关闭文件描述符表)

    while(1)
    {}
    return 0;
}

这里写图片描述
可以看到PPID为1,因为我们把父进程进程直接退出,它为孤儿进程被init接受,它没有终端,TPGID为-1;

为什么有人fork两次

我们在了解为什么fork两次,先看看第一次和此二次fork都起到什么作用:
(1)调用一次fork的作用:
第一次fork()的作用是让shell认为这条命令已经终止,不用挂在终端输入上,还有就是为了后面的setsid服务,应为调用setsid函数的进程不能是组长进程,当子进程调用完setsid函数之后,子进程是会话组长也是进程组组长,并且脱离了控制终端,此时,不管控制终端如何操作,新的进程都不会受到一些信号使得进程退出;
(2)第二次fork()的作用:
虽然当前关闭了和终端的联系,但是后期可能会误操作打开了终端。只有会话首进程能打开终端设备,也就是再fork一次,再把父进程退出,再次fork的子进程必须作为守护进程继续运行,保证了该守护进程不是对话期的首进程。
第二次fork不是必须的,是可选的:

void mydaemon()
{
    umask(0);
    if(fork() == 0)
    {}
    else
    {
        exit(0);
    }
    setsid();
    if(fork() < 0)
    {
        return;
    }
    else if(fork() != 0)
    {
        exit(0);
    }
    chdir("/");
    close(0);
    close(1);
    close(2);
    signal(SIGCHLD, SIG_IGN);
}

这里写图片描述
现在就回有两个守护进程,一个时第一次fork的,一个时第二次fork的,可以看出他们在同一个进程组中,同一个会话组中。

<think>好的,我现在需要回答用户关于守护进程的问题。用户想了解守护进程的概念、创建方法以及应用场景。首先,我得先理清楚这些部分的结构,确保信息准确且符合用户的要求。 首先,守护进程的概念。根据用户提供的引用,守护进程是在后台运行的特殊进程,不依赖终端,通常在系统启动时启动,处理系统级任务。我需要明确这一点,可能还要提到它和普通进程的区别,比如不与用户交互,独立于控制终端等。 然后是创建方法。用户提供的引用中有提到Python创建守护进程的代码,特别是两次fork的原因,还有umask设置、进程组、会话组等。这里需要详细解释创建守护进程的步骤,比如第一次fork脱离终端,setsid创建新会话,第二次fork避免重新获取终端,修改工作目录,关闭文件描述符等。同时要注意引用中的代码示例,可能需要简化或者用文字描述过程,而不用实际代码,因为用户可能更关注步骤而非具体实现。 应用场景部分,引用的资料提到了系统服务、后台任务处理、嵌入式系统中的设备管理和网络通信等。需要分点说明,每个场景给出具体例子,比如http服务器、定时任务、日志监控等,这样用户更容易理解。 另外,用户要求生成相关问题,我需要根据内容提出几个相关的问题,比如与后台进程的区别、创建中的关键步骤、在嵌入式中的应用等。这些问题应该能够帮助用户进一步深入学习。 需要注意LaTeX格式是否正确,数学表达式要用$...$,不过这个问题可能不涉及太多数学内容,但如果有的话需要检查。另外,回答结构要清晰,分点说明,帮助用户逐步理解。 可能还需要对比守护进程和后台进程的区别,引用中提到两者的区别,比如生命周期、终端关联性、使用场景等。这部分可以作为补充信息,帮助用户更好地区分概念。 最后,确保引用标识正确添加到相关段落的末尾,比如在提到创建步骤时引用[^1],应用场景引用[^3]等。同时检查是否有遗漏的信息,比如守护进程的资源管理或者常见问题,但根据用户提供的引用,可能不需要深入这些方面。 总结一下,回答的结构应该是: 1. 守护进程的概念 2. 创建步骤(重点) 3. 应用场景 4. 相关问题 每个部分需要简明扼要,引用正确,并符合用户的要求。现在开始组织语言,确保每个部分清晰,符合中文表达,避免技术术语过于晦涩,同时保持专业性。</think>### 守护进程详解 #### 1. **概念** **守护进程Daemon)** 是一种在后台长期运行的特殊进程,独立于终端控制,通常在系统启动时自动初始化,负责处理系统级任务(如日志管理、网络服务等)。其核心特征包括: - 不依赖用户终端(即使终端关闭仍持续运行) - 生命周期与系统一致(常驻内存直到系统关闭) - 以 root 权限或特定用户身份运行[^2][^3] #### 2. **创建方法** 创建守护进程需遵循以下步骤(以 Linux 系统为例): **步骤 1:第一次 `fork`** 通过 `fork()` 创建子进程并结束父进程,使子进程脱离终端控制: ```python import os pid = os.fork() if pid > 0: os._exit(0) # 终止父进程 ``` **步骤 2:创建新会话组** 调用 `setsid()` 使子进程成为新会话组和进程组的领导者,完全脱离原终端关联: ```python os.setsid() ``` **步骤 3:第二次 `fork`** 再次 `fork()` 确保进程无法重新获取终端(避免成为会话组长): ```python pid = os.fork() if pid > 0: os._exit(0) ``` **步骤 4:设置工作目录与文件权限掩码** - 修改工作目录为根目录:`os.chdir("/")` - 重置 `umask` 权限掩码:`os.umask(0)` **步骤 5:关闭文件描述符** 关闭继承的文件描述符(如标准输入/输出/错误流): ```python import sys sys.stdin.close() sys.stdout.close() sys.stderr.close() ``` 完整代码示例可参考引用。 #### 3. **应用场景** - **系统服务**:如 Web 服务器(Nginx)、数据库服务(MySQL)等[^2] - **后台任务处理**:定时任务(cron)、日志轮转(logrotate) - **嵌入式系统**:设备状态监控、传感器数据采集、网络通信守护 - **资源管理**:内存清理、进程调度守护程序 #### 4. **与后台进程的区别** | **特征** | **守护进程** | **后台进程** | |----------------|--------------------------|--------------------------| | 生命周期 | 长期运行,随系统启动/关闭 | 依赖用户会话(终端退出则终止) | | 终端关联性 | 完全独立 | 通过 `&` 启动但仍关联终端 | | 典型应用 | 系统级服务 | 用户临时任务(如长时间计算) | ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值