Linux 守护进程

简介: Linux 守护进程

Linux 守护进程又称为 Daemon 进程,为 Linux 的后台服务进程(独立于控制终端)。该进程通常周期性地执行某种任务或等待处理某些发生的事件。其生命周期较长,通常在系统启动时开始执行,在系统关闭时终止。 Linux 中很多系统服务都是通过守护进程实现的。


Linux 中,每一个从终端开始运行的进程都会依附于一个终端(系统与用户进行交互的界面),这个终端为进程的控制终端。当控制终端关闭时,这些进程就会自动结束,但守护进程不受终端关闭的影响。


如何将一个进程变成一个守护进程,只需要遵循一些特定的流程,下面通过 5 个步骤来讲解。


Step1. 创建子进程(子进程不退出,父进程退出)

很明显,由于父进程先于子进程退出,造成子进程成为孤儿进程。此时子进程的父进程变成 init/systemd 进程。


Step2. 在子进程中创建新会话

这个步骤在进程组与会话组中已经有所介绍,使用的函数是 setsid() 。该函数将会创建一个新会话,并使进程担任该会话组的组长。同时,在会话组中创建新的进程组,该进程依然也是进程组的组长。该进程成为新会话组和进程组中唯一的进程。最后使该进程脱离终端的控制,运行在后台。


之所以需要这样处理,是因为子进程在被创建时,复制了父进程的会话、进程组和终端控制等。虽然父进程退出,但原先的会话、进程组和控制终端等并没有改变。因此,子进程并没有实现真正意义上的独立。


Step3. 改变当前的工作目录

使用 fork() 函数创建的子进程继承了父进程的当前工作目录。系统通常的做法是让根目录成为守护进程的当前工作目录。改变工作目录的函数是 chdir()

#include <unistd.h>
int chdir(const char *path);点击复制复制失败已复制


Step4. 重设文件权限掩码

文件权限掩码的作用是屏蔽文件权限中的对应位。在文件的打开和关闭中有涉及该问题。文件被创建后,其用户操作权限 mode ,将会被执行 mode&~umask ( umask 为文件权限掩码,通常用八进制数表示)。例如,文件的权限为 0666umask 值为 0002 ,那么将 umask 取反,再与文件权限相与,则文件权限值变为 0664 。由于创建的子进程继承父进程的文件权限掩码,这给子进程(守护进程)操作文件带来一定影响。因此,通常把文件权限掩码设置为 0 ,这样可以增强守护进程的灵活性。此时,文件权限掩码取反全为 1 ,与任何文件权限相与,都可保持文件最原始的状态值。


使用函数 umask() ,改变文件权限掩码,参数即为要修改的掩码值。

#include <sys/types.h>
#include <sys/stat.h>
mode_t umask(mode_t mask);点击复制复制失败已复制


Step5. 关闭文件描述符

新创建的子进程会从父进程继承一些已经打开的文件描述符。这些描述符可能永远不会被守护进程访问,但它们却占有一定的资源。特别需要注意的是,守护进程脱离了终端的控制,所以与终端相关的标准输入、输出、错误输出的文件描述符 012 ,已经没有了任何价值,应对关闭。具体如下所示:

int num;
num = getdtablesize();  // 获取当前进程文件描述符表大小
for (i = 0; i < num; i++){
  close(i);
}点击复制复制失败已复制


其中, getdtablesize() 函数的功能为获取文件描述符表的大小,也可以理解为获取进程打开的文件描述符的最大数量。


实现

通过以上 5 步,可以实现创建守护进程,其流程如下:

微信截图_20221209152630.png


守护进程的代码具体如下所示,守护进程每隔 3 秒向日志文件 "/tmp/daemon.log" 中写入字符串。

#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
int main(int argc, const char *argv[]) {
  pid_t pid;
  int i, fd;
  char *buf = "This is a Daemon\n";
  pid = fork(); // 第一步
  if (pid < 0) {
    perror("fork error");
    return -1;
  } else if (pid > 0) {
    exit(0); // 父进程退出
  } else {
    setsid();      // 第二步
    chdir("/tmp"); // 第三步
    umask(0);      // 第四步
    for (i = 0; i < getdtablesize(); i++) {
      close(i); // 第五步
    }
    if ((fd = open("daemon.log", O_CREAT | O_WRONLY | O_TRUNC, 0600)) < 0) {
      perror("open error");
      return -1;
    }
    while (1) {
      write(fd, buf, strlen(buf));
      sleep(3);
    }
    close(fd);
  }
  return 0;
}点击复制复制失败已复制


编译并运行,可以看到终端直接退出,接下来查看 /tmp/daemon.log 文件,可以看到日志内容:

This is a Daemon
This is a Daemon
This is a Daemon
This is a Daemon
This is a Daemon
……点击复制复制失败已复制


终端查看进程信息如下:

$ ps axj | grep ./a.out
   PPID     PID    PGID     SID TTY        TPGID STAT   UID   TIME COMMAND
   1202  496227  496227  496227 ?             -1 Ss    1000   0:00 ./a.out
$ ps axj | grep systemd
   PPID     PID    PGID     SID TTY        TPGID STAT   UID   TIME COMMAND
      1    1202    1202    1202 ?             -1 Ss    1000   0:00 /lib/systemd/systemd --user点击复制复制失败已复制


可以看出进程的 ID 与组 ID 、会话 ID 保持一致,说明当前守护进程为组长。其父进程为 systemd 进程, TTY 选项为 "?" ,表示其为后台进程

目录
相关文章
|
28天前
|
算法 Linux 调度
深入理解Linux操作系统的进程管理
本文旨在探讨Linux操作系统中的进程管理机制,包括进程的创建、执行、调度和终止等环节。通过对Linux内核中相关模块的分析,揭示其高效的进程管理策略,为开发者提供优化程序性能和资源利用率的参考。
66 1
|
17天前
|
存储 监控 Linux
嵌入式Linux系统编程 — 5.3 times、clock函数获取进程时间
在嵌入式Linux系统编程中,`times`和 `clock`函数是获取进程时间的两个重要工具。`times`函数提供了更详细的进程和子进程时间信息,而 `clock`函数则提供了更简单的处理器时间获取方法。根据具体需求选择合适的函数,可以更有效地进行性能分析和资源管理。通过本文的介绍,希望能帮助您更好地理解和使用这两个函数,提高嵌入式系统编程的效率和效果。
79 13
|
23天前
|
SQL 运维 监控
南大通用GBase 8a MPP Cluster Linux端SQL进程监控工具
南大通用GBase 8a MPP Cluster Linux端SQL进程监控工具
|
1月前
|
运维 监控 Linux
Linux操作系统的守护进程与服务管理深度剖析####
本文作为一篇技术性文章,旨在深入探讨Linux操作系统中守护进程与服务管理的机制、工具及实践策略。不同于传统的摘要概述,本文将以“守护进程的生命周期”为核心线索,串联起Linux服务管理的各个方面,从守护进程的定义与特性出发,逐步深入到Systemd的工作原理、服务单元文件编写、服务状态管理以及故障排查技巧,为读者呈现一幅Linux服务管理的全景图。 ####
|
2月前
|
缓存 监控 Linux
linux进程管理万字详解!!!
本文档介绍了Linux系统中进程管理、系统负载监控、内存监控和磁盘监控的基本概念和常用命令。主要内容包括: 1. **进程管理**: - **进程介绍**:程序与进程的关系、进程的生命周期、查看进程号和父进程号的方法。 - **进程监控命令**:`ps`、`pstree`、`pidof`、`top`、`htop`、`lsof`等命令的使用方法和案例。 - **进程管理命令**:控制信号、`kill`、`pkill`、`killall`、前台和后台运行、`screen`、`nohup`等命令的使用方法和案例。
153 4
linux进程管理万字详解!!!
|
2月前
|
缓存 算法 Linux
Linux内核的心脏:深入理解进程调度器
本文探讨了Linux操作系统中至关重要的组成部分——进程调度器。通过分析其工作原理、调度算法以及在不同场景下的表现,揭示它是如何高效管理CPU资源,确保系统响应性和公平性的。本文旨在为读者提供一个清晰的视图,了解在多任务环境下,Linux是如何智能地分配处理器时间给各个进程的。
|
2月前
|
存储 运维 监控
深入Linux基础:文件系统与进程管理详解
深入Linux基础:文件系统与进程管理详解
90 8
|
2月前
|
网络协议 Linux 虚拟化
如何在 Linux 系统中查看进程的详细信息?
如何在 Linux 系统中查看进程的详细信息?
155 1
|
2月前
|
Linux
如何在 Linux 系统中查看进程占用的内存?
如何在 Linux 系统中查看进程占用的内存?
|
2月前
|
算法 Linux 定位技术
Linux内核中的进程调度算法解析####
【10月更文挑战第29天】 本文深入剖析了Linux操作系统的心脏——内核中至关重要的组成部分之一,即进程调度机制。不同于传统的摘要概述,我们将通过一段引人入胜的故事线来揭开进程调度算法的神秘面纱,展现其背后的精妙设计与复杂逻辑,让读者仿佛跟随一位虚拟的“进程侦探”,一步步探索Linux如何高效、公平地管理众多进程,确保系统资源的最优分配与利用。 ####
75 4