0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

Linux中如何编写守护进程程序

麦辣鸡腿堡 来源:嵌入式Linux系统开发 作者:Jasonangel 2023-10-07 17:12 次阅读

守护进程(Daemon)也称为精灵进程,是运行在后台的一种特殊进程,它独立于控制终端并且周期性地执行某种任务或等待处理某些事情的发生,主要表现为以下两个特点:

⚫ 长期运行。守护进程是一种生存期很长的一种进程,它们一般在系统启动时开始运行,除非强行终止,否则直到系统关机都会保持运行。与守护进程相比,普通进程都是在用户登录或运行程序时创建,在运行结束或用户注销时终止,但守护进程不受用户登录注销的影响,它们将会一直运行着、直到系统关机。

⚫ 与控制终端脱离。在 Linux 中,系统与用户交互的界面称为终端,每一个从终端开始运行的进程都会依附于这个终端,这是上一小节给大家介绍的控制终端,也就是会话的控制终端。当控制终端被关闭的时候,该会话就会退出,由控制终端运行的所有进程都会被终止,这使得普通进程都是和运行该进程的终端相绑定的;但守护进程能突破这种限制,它脱离终端并且在后台运行,脱离终端的目的是为了避免进程在运行的过程中的信息在终端显示并且进程也不会被任何终端所产生的信息所打断。

守护进程是一种很有用的进程。Linux 中大多数服务器就是用守护进程实现的,譬如,Internet 服务器 inetd、Web 服务器 httpd 等。同时,守护进程完成许多系统任务,譬如作业规划进程 crond 等。

守护进程 Daemon,通常简称为 d,一般进程名后面带有 d 就表示它是一个守护进程。守护进程与终端无任何关联,用户的登录与注销与守护进程无关、不受其影响,守护进程自成进程组、自成会话,即pid=gid=sid。通过命令"ps -ajx"查看系统所有的进程,如下所示:

图片TTY 一栏是问号?表示该进程没有控制终端,也就是守护进程,其中 COMMAND 一栏使用中括号[]括起来的表示内核线程,这些线程是在内核里创建,没有用户空间代码,因此没有程序文件名和命令行,通常采用 k 开头的名字,表示 Kernel。

编写守护进程程序

  1. 创建子进程、终止父进程。父进程调用 fork()创建子进程,然后父进程使用 exit()退出,这样做实现了下面几点。第一,如果该守护进程是作为一条简单地 shell 命令启动,那么父进程终止会让 shell 认为这条命令已经执行完毕。第二,虽然子进程继承了父进程的进程组ID,但它有自己独立的进程ID,这保证了子进程不是一个进程组的组长进程,这是下面将要调用 setsid 函数的先决条件!
  2. 子进程调用 setsid 创建会话。setsid()函数创建新的会话,由于之前子进程并不是进程组的组长进程,所以调用 setsid()会使得子进程创建一个新的会话,子进程成为新会话的首领进程,同样也创建了新的进程组、子进程成为组长进程,此时创建的会话将没有控制终端。所以这里调用 setsid 有三个作用:让子进程摆脱原会话的控制、让子进程摆脱原进程组的控制和让子进程摆脱原控制终端的控制。在调用 fork 函数时,子进程继承了父进程的会话、进程组、控制终端等,虽然父进程退出了,但原先的会话期、进程组、控制终端等并没有改变,因此,那还不是真正意义上使两者独立开来。setsid 函数能够使子进程完全独立出来,从而脱离所有其他进程的控制。
  3. 将工作目录更改为根目录。子进程是继承了父进程的当前工作目录,由于在进程运行中,当前目录所在的文件系统是不能卸载的,这对以后使用会造成很多的麻烦。因此通常的做法是让“/”作为守护进程的当前目录,当然也可以指定其 它目录来作为守护进程的工作目录。
  4. 重设文件权限掩码 umask。文件权限掩码 umask 用于对新建文件的权限位进行屏蔽,在 5.5.5 小节中有介绍。由于使用 fork 函数新建的子进程继承了父进程的文件权限掩码,这就给子进程使用文件带来了诸多的麻烦。因此,把文件权限掩 码设置为 0,确保子进程有最大操作权限、这样可以大大增强该守护进程的灵活性。设置文件权限掩码的函数是 umask,通常的使用方法为 umask(0)。
  5. 关闭不再需要的文件描述符。子进程继承了父进程的所有文件描述符,这些被打开的文件可能永远不会被守护进程(此时守护进程指的就是子进程,父进程退出、子进程成为守护进程)读或写,但它们一样消耗系统资源,可能导致所在的文件系统无法卸载,所以必须关闭这些文件,这使得守护进程不再持有从其父进程继承过来的任何文件描述符。
  6. 将文件描述符号为 0、1、2 定位到/dev/null。将守护进程的标准输入、标准输出以及标准错误重定向到/dev/null,这使得守护进程的输出无处显示、也无处从交互式用户那里接收输入。
  7. 忽略 SIGCHLD 信号。处理 SIGCHLD 信号不是必须的,但对于某些进程,特别是并发服务器进程往往是特别重要的,服务器进程在接收到客户端请求时会创建子进程去处理该请求,如果子进程结束之后,父进程没有去 wait 回收子进程,则子进程将成为僵尸进程;如果父进程 wait 等待子进程退出,将又会增加父进程的负担、也就是增加服务器的负担,影响服务器进程的并发性能,在 Linux 下,可以将 SIGCHLD 信号的处理方式设置为SIG_IGN,也就是忽略该信号,可让内核将僵尸进程转交给 init 进程去处理,这样既不会产生僵尸进程、又省去了服务器进程回收子进程所占用的时间。
#include < stdio.h >
#include < stdlib.h >
#include < unistd.h >
#include < sys/types.h >
#include < sys/stat.h >
#include < fcntl.h >
#include < signal.h >
int main(void) {
   pid_t pid;
   int i;
   /* 创建子进程 */
   pid = fork();
   if (0 > pid) {
     perror("fork error");
     exit(-1);
   }
   else if (0 < pid)//父进程
     exit(0); //直接退出
   /*
   *子进程
   */
   /* 1.创建新的会话、脱离控制终端 */
   if (0 > setsid()) {
   perror("setsid error");
   exit(-1);
   }
   /* 2.设置当前工作目录为根目录 */
   if (0 > chdir("/")) {
     perror("chdir error");
     exit(-1);
   }
   /* 3.重设文件权限掩码 umask */
   umask(0);
   /* 4.关闭所有文件描述符 */
   for (i = 0; i < sysconf(_SC_OPEN_MAX); i++)
     close(i);
   /* 5.将文件描述符号为 0、1、2 定位到/dev/null */
   open("/dev/null", O_RDWR);
   dup(0);
   dup(0);
   /* 6.忽略 SIGCHLD 信号 */
   signal(SIGCHLD, SIG_IGN);
   /* 正式进入到守护进程 */
   for ( ; ; ) {
     sleep(1);
     puts("守护进程运行中......");
   }
   exit(0);
}

整个代码的编写都是根据上面的介绍来完成的。运行之后,没有任何打印信息输出,原因在于守护进程已经脱离了控制终端,它的打印信息并不会输出显示到终端,在代码中已经将标准输入、输出以及错误重定位到了/dev/null,/dev/null 是一个黑洞文件,自 然是看不到输出信息。

守护进程可以通过终端命令行启动,但通常它们是由系统初始化脚本进行启动,譬如/etc/rc*或 /etc/init.d/*等。

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • Linux
    +关注

    关注

    87

    文章

    11222

    浏览量

    208883
  • 终端
    +关注

    关注

    1

    文章

    1114

    浏览量

    29828
  • 程序
    +关注

    关注

    116

    文章

    3773

    浏览量

    80835
  • 系统
    +关注

    关注

    1

    文章

    1006

    浏览量

    21310
收藏 人收藏

    评论

    相关推荐

    Linux守护进程

    1.守护进程概述 守护进程,也就是通常所说的daemon进程,是Linux
    发表于 08-22 09:17

    Linux进程间通信方式-管道

    应用程序开发》热点链接:1、Linux进程间通信2、实验:编写守护进程3、实验:
    发表于 08-29 15:29

    实验:编写进程程序

    1.实验目的 通过编写进程程序,使读者熟练掌握fork()、exec()、wait()和waitpid()等函数的使用,进一步理解在Linux
    发表于 09-05 15:32

    Linux学习杂谈】之守护进程以及简单创建

    首先我们需要了解一下什么叫做守护进程,以及我们为什么需要这样的进程。我们知道当我们写一个简单的程序的时候我们知道,这个程序比如说printf
    发表于 09-27 13:28

    初学者嵌入式linux系统的学习步骤

    /O 编写串口通信程序 编写多串口通信程序7、嵌入式系统进程
    发表于 01-18 10:34

    Linux守护进程详解

    分享到:标签:进程控制 Linux 守护进程进程 7.3 Linux
    发表于 10-18 14:24 0次下载
    <b class='flag-5'>Linux</b><b class='flag-5'>守护</b><b class='flag-5'>进程</b>详解

    进程控制开发之编写进程程序实验解析

    7.4.1 编写进程程序 1.实验目的 通过编写进程程序,使读者熟练掌握fork()、exe
    发表于 10-18 16:33 0次下载
    <b class='flag-5'>进程</b>控制开发之<b class='flag-5'>编写</b>多<b class='flag-5'>进程</b><b class='flag-5'>程序</b>实验解析

    Linux系统网络驱动程序编写

    驱动程序编写 一.Linux系统设备驱动程序概述 1.1 Linux设备驱动程序分类 1.2
    发表于 11-07 10:40 0次下载

    嵌入式linux系统的学习步骤

    串口通信 熟悉文件I/O 编写串口通信程序 编写多串口通信程序 7、嵌入式系统进程
    发表于 07-23 13:59 967次阅读

    你知道嵌入式linux系统下简单守护进程(daemon)的编写

    嵌入式linux设备创建一个守护进程,用于保护系统的主进程,防止某些不可预期的意外导致主
    发表于 04-23 15:16 1402次阅读
    你知道嵌入式<b class='flag-5'>linux</b>系统下简单<b class='flag-5'>守护</b><b class='flag-5'>进程</b>(daemon)的<b class='flag-5'>编写</b>?

    学会用日志了解你的 Linux 系统

    Linux 系统日志非常重要,后台运行的程序(通常被称为守护进程或者服务进程)处理了你 Linux
    发表于 05-06 16:39 720次阅读

    linux守护进程实例

      今天完成一个守护进程实验。  1 熟悉守护进程编写和调试(系统日志)  2 编写
    发表于 04-02 14:42 388次阅读

    如何编写基于ARM的裸机程序和基于Linux的驱动程序

    在嵌入式开发,ADC应用比较频繁,本文主要讲解ADC的基本原理以及如何编写基于ARM的裸机程序和基于Linux的驱动程序
    的头像 发表于 09-13 09:25 3288次阅读
    如何<b class='flag-5'>编写</b>基于ARM的裸机<b class='flag-5'>程序</b>和基于<b class='flag-5'>Linux</b>的驱动<b class='flag-5'>程序</b>

    Linux 安全模块:守护进程和套接字

    守护进程通常是在后台观察操作以等待状态、服务于特定子系统并确定整个系统的操作规则的实用程序。例如,一个守护进程被配置为监控打印服务的状态。
    发表于 08-26 10:01 651次阅读

    文盘Rust--把程序作为守护进程启动

    当我们写完一个服务端程序,需要上线部署的时候,或多或少都会和操作系统的守护进程打交道,毕竟谁也不希望shell关闭既停服。今天我们就来聊聊这个事儿。
    的头像 发表于 11-07 10:22 1040次阅读