Linux守护进程(Daemon)介绍与实现

1. 守护进程简介

守护进程(deamon)是生存期长的一种进程。它们常常在系统引导装入时启动(如果需要守护进程随系统自启动,需要在/etc/init.d目录下放置响应的启动脚本,或者利用systemctl来控制,还有一些其他方法如supervisor等),仅在系统关闭时才终止。因为它们没有控制终端,所以说它们是在后台运行的。
  从daemon的启动和管理方式区分,可以将daemon分为两大类:可独立启动的daemon(stand alone)和由一个超级daemon(super daemon)来统一管理的daemon。

  • stand alone:可单独自行启动的daemon。这种daemon启动后会一直占用内存和系统资源,最大的优点是响应速度快,多用于能够随时接受远程请求的服务,如WWW的daemon(httpd)、FTP的daemon(vsftpd)等。
  • super daemon:由一个特殊的daemon来统一管理。这种服务通过一个统一的daemon在需要时负责唤醒,当没有远程请求时,这些服务都是未启动的,等到有远程请求过来时,super daemon才唤醒相应的服务。当远程请求结束后,被唤醒的服务会关闭并释放系统资源。早期的super daemon是inetd,后来被xinetd替代了。super daemon本身是一个stand alone的服务,因为它需要管理后续的其他服务,所以它自己本身当然需要常驻内存中。

2. 守护进程的实现步骤

  1. 执行一个fork(),之后父进程退出,子进程继续执行。(结果就是daemon成为了init进程的子进程。)
    之所以要做这一步是因为下面两个原因:
    • 假设daemon是从命令行启动的,父进程的终止会被shell发现,shell在发现之后会显示出另一个shell提示符并让子进程继续在后台运行。
    • 子进程被确保不会称为一个进程组组长进程,因为它从其父进程那里继承了进程组ID并且拥有了自己的唯一的进程ID,而这个进程ID与继承而来的进程组ID是不同的,这样才能够成功地执行下面一个步骤。
  2. 子进程调用setsid()开启一个新回话并释放它与控制终端之间的所有关联关系。 结果就是使子进程: (a)成为新会话的首进程,(b)成为一个新进程组的组长进程,©没有控制终端。
  3. 如果daemon从来没有打开过终端设备,那么就无需担心daemon会重新请求一个控制终端了。如果daemon后面可能会打开一个终端设备,那么必须要采取措施来确保这个设备不会成为控制终端。这可以通过下面两种方式实现:
    • 在所有可能应用到一个终端设备上的open()调用中指定O_NOCTTY标记。
    • 或者更简单地说,在setsid()调用之后执行第二个fork(),然后再次让父进程退出并让孙子进程继续执行。这样就确保了子进程不会称为会话组长,因此根据System V中获取终端的规则,进程永远不会重新请求一个控制终端。(多一个fork()调用不会带来任何坏处。)
  4. 清除进程的umask以确保当daemon创建文件和目录时拥有所需的权限。
  5. 修改进程的当前工作目录,通常会改为根目录(/)。这样做是有必要的,因为daemon通常会一直运行直至系统关闭为止。如果daemon的当前工作目录为不包含/的文件系统,那么就无法卸载该文件系统。或者daemon可以将工作目录改为完成任务时所在的目录或在配置文件中定义一个目录,只要包含这个目录的文件系统永远不会被卸载即可。
  6. 关闭daemon从其父进程继承而来的所有打开着的文件描述符。(daemon可能需要保持继承而来的文件描述的打开状态,因此这一步是可选的或者可变更的。)之所以这样做的原因有很多。由于daemon失去了控制终端并且是在后台运行的,因此让daemon保持文件描述符0(标准输入)、1(标准输出)和2(标准错误)的打开状态毫无意义,因为它们指向的就是控制终端。此外,无法卸载长时间运行的daemon打开的文件所在的文件系统。因此,通常的做法是关闭所有无用的打开着的文件描述符,因为文件描述符是一种有限的资源。
  7. 在关闭了文件描述符0、1和2之后,daemon通常会打开/dev/null并使用dup2()(或类似的函数)使所有这些描述符指向这个设备。之所以要这样做是因为下面两个原因:
    • 它确保了当daemon调用了在这些描述符上执行I/O的库函数时不会出乎意料地失败。
    • 它防止了daemon后面使用描述符1或2打开一个文件的情况,因为库函数会将这些描述符当做标准输出和标准错误来写入数据(进而破坏了原有的数据)。

3. c++的实现

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值