守护进程(精灵进程)

1.守护进程的概念及相关的概念

守护进程也叫精灵进程,指的是脱离终端,独立运行在后台,长期运行,用来提供服务的进程。

守护进程的特点:

1.不依赖任何终端(关闭终端守护进程而不会退出)。

2.父进程通常是init或者是systemd;

3.用于提供服务,网络服务,定时服务等。

1. 进程组(Process Group)
  • 定义:一个或多个进程的集合,用于统一管理(如发送信号)。
  • 特点:
    • 每个进程组有唯一的进程组 ID(PGID)
    • 进程组的生命周期从创建开始,到最后一个进程离开(终止或加入其他组)结束。
2. 组长进程(Process Group Leader)
  • 定义:进程组的创建者,其PID = PGID
  • 特点:组长进程可以创建进程组和组内进程,但组长进程终止不会影响进程组(只要还有其他进程存在)。
3. 会话(Session)
  • 定义:一个或多个进程组的集合,通常与一个终端关联(控制终端)。
  • 特点:
    • 每个会话有唯一的会话 ID(SID)
    • 一个会话最多有一个控制终端(用于输入输出);
    • 会话中的进程组分为前台进程组 (与终端交互)和后台进程组(不交互)。
4. 会话首进程(Session Leader)
  • 定义:会话的创建者,其PID = SID
  • 特点:只有会话首进程能重新获取控制终端(这也是守护进程需要二次 fork 的原因)。

二、详细解析守护进程实现步骤

1. 第一次 fork()
  • 作用:让父进程退出,子进程继续运行。
  • 原因
    • 父进程通常是 shell 进程,退出后子进程变成孤儿进程,由init/systemd收养;
    • 确保子进程不是进程组组长(为后续setsid创造条件,因为组长进程不能创建新会话)。
2. setsid()
  • 作用:创建一个新会话,使子进程成为新会话的首进程和新进程组的组长,并脱离原控制终端。
  • 底层逻辑
    • 新会话的 SID = 子进程 PID;
    • 新进程组的 PGID = 子进程 PID;
    • 子进程不再关联任何控制终端。
3. 第二次 fork()
  • 作用:让子进程(会话首进程)退出,孙进程继续运行。
  • 原因
    • 会话首进程可以重新获取控制终端,二次 fork 后孙进程不再是会话首进程,彻底避免重新关联终端;
    • 进一步确保守护进程的独立性。
4. chdir("/")
  • 作用:将工作目录切换到根目录。
  • 原因
    • 守护进程长期运行,若工作目录在其他文件系统(如 U 盘),会导致该文件系统无法卸载;
    • 根目录始终存在,安全性高。
5. umask(0)
  • 作用:将文件权限掩码设为 0。
  • 原因
    • 守护进程可能需要创建文件,继承的权限掩码(如 022)会限制文件权限;
    • 设为 0 后,创建文件时权限完全由open/creat的参数决定(如0644)。
6. close() 关闭文件描述符
  • 作用:关闭从父进程继承的所有文件描述符(尤其是 0、1、2,对应标准输入、输出、错误)。
  • 原因
    • 守护进程脱离终端,这些文件描述符不再使用,浪费资源;
    • 避免后续操作(如open)意外使用这些描述符导致错误。
  • 优化 :通常关闭0-2后,将它们重定向到/dev/null(空设备),防止程序因读写标准 IO 出错。

三、守护进程代码演示(C 语言)

cpp 复制代码
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <signal.h>
#include <syslog.h>

void create_daemon() {
    pid_t pid;

    // 1. 第一次fork
    pid = fork();
    if (pid < 0) {
        perror("fork failed");
        exit(EXIT_FAILURE);
    }
    if (pid > 0) {
        exit(EXIT_SUCCESS); // 父进程退出
    }

    // 2. 创建新会话
    if (setsid() < 0) {
        perror("setsid failed");
        exit(EXIT_FAILURE);
    }

    // 3. 忽略SIGHUP信号(防止会话首进程退出时孙进程被终止)
    signal(SIGHUP, SIG_IGN);

    // 4. 第二次fork
    pid = fork();
    if (pid < 0) {
        perror("second fork failed");
        exit(EXIT_FAILURE);
    }
    if (pid > 0) {
        exit(EXIT_SUCCESS); // 会话首进程退出
    }

    // 5. 切换工作目录到根目录
    if (chdir("/") < 0) {
        perror("chdir failed");
        exit(EXIT_FAILURE);
    }

    // 6. 设置文件权限掩码为0
    umask(0);

    // 7. 关闭所有继承的文件描述符
    // 先获取最大文件描述符数
    int max_fd = sysconf(_SC_OPEN_MAX);
    if (max_fd == -1) {
        max_fd = 1024; // 默认值
    }
    for (int i = 0; i < max_fd; i++) {
        close(i);
    }

    // 8. 重定向0、1、2到/dev/null
    open("/dev/null", O_RDWR); // 0
    dup(0); // 1
    dup(0); // 2

    // 9. 初始化syslog(用于守护进程日志输出)
    openlog("mydaemon", LOG_PID, LOG_DAEMON);
}

int main() {
    create_daemon();

    // 守护进程的核心逻辑:每隔10秒写一条日志
    while (1) {
        syslog(LOG_INFO, "Daemon is running...");
        sleep(10);
    }

    closelog();
    return 0;
}
代码解析
  1. 第一次 fork:父进程退出,子进程成为孤儿进程。
  2. setsid:子进程成为新会话和新进程组的组长,脱离终端。
  3. 忽略 SIGHUP:防止第二次 fork 后,会话首进程退出时孙进程收到 SIGHUP 信号被终止。
  4. 第二次 fork:孙进程不再是会话首进程,彻底避免重新关联终端。
  5. chdir("/"):切换到安全的根目录。
  6. umask(0):确保文件创建权限不受限制。
  7. 关闭文件描述符:释放资源,避免意外操作。
  8. 重定向到 /dev/null:让标准 IO 操作 "空转",防止程序出错。
  9. syslog :守护进程无法使用 printf,通过 syslog 将日志写入系统日志(/var/log/syslog/var/log/messages)。

四、补充:守护进程的管理

  1. 查看守护进程

    复制代码
    ps aux | grep mydaemon
  2. 查看日志

    复制代码
    tail -f /var/log/syslog
  3. 终止守护进程

    复制代码
    kill <daemon_pid>
相关推荐
CableTech_SQH4 分钟前
商业地产和高端酒店该怎么选综合布线解决方案?
运维·服务器·网络
Y\8 分钟前
VMware虚拟机已断开连接解决方法(二)
服务器
isyangli_blog12 分钟前
vmware 安装 Windows Server 2012
服务器
怀旧,31 分钟前
【Linux网络编程】9. 数据链路层
linux·服务器·网络
QotomPC43 分钟前
Qotom Q30900GP多网口Mini PC:16网口设计在pfSense与工业网络中的应用
服务器·网络·边缘计算
用户2367829801681 小时前
Linux watch 命令深度解析:从实时监控到变化检测的完整实现
linux
xingyuzhisuan1 小时前
哪里可以一键部署Stable Diffusion XL的GPU云环境?(2026实测指南)
运维·人工智能·stable diffusion·gpu算力
Agent手记1 小时前
采购合同智能审核自动化,落地步骤与落地风险管控方案 —— 2026年企业级Agent深度实战指南
运维·人工智能·ai·自动化
Liangwei Lin1 小时前
LeetCode 22. 括号生成
linux·运维·服务器
win水1 小时前
八、命令行参数和环境变量
linux·环境变量·命令行参数