什么是Daemon

Daemon程序,又称为守护进程,通常在系统后台长时间运行,由于没有控制终端而无法与前台交互。Daemon程序一般作为系统服务使用。Unix/Linux中的daemon进程类似于Windows中的后台服务进程,例如http服务进程nginx,ssh服务进程sshd等。

ps -axj 命令打印系统中各进程的状态。
选择项- a显示由其他用户所拥有的进程的状态。
-x显示没有控制终端的进程的状态。
-j显示与作业有关的信息:对话期 ID、进程组ID、控制终端以及终端进程组 ID。

.

进程0,1,2,这些进程非常特殊,存在于系统的整个生命期中。 它们没有父进程ID,没有组进程ID,也没有对话期ID。

进程ID0是调度进程,常常被称为交换进程(swapper)。该进程并不执行任何磁盘上的程序—它是内核的一部分,因此也被称为系统进程。

进程ID1通常是init进程,在自举过程结束时由内核调用。该进程的程序文件在UNIX的早期版本中是/etc/init,在较新版本中是/sbin/init。此进程负责在内核自举后起动一个UNIX系统.init通常读与系统有关的初始化文件(/etc/rc*文件),并将系统引导到一个状态(例如多用户)。init进程决不会终止。它是一个普通的用户进程(与交换进程不同,它不是内核中的系统进程 ),但是它以超级用户特权运行。

在某些UNIX的虚存实现中,进程ID 2是页守护进程( pagedaemon)。此进程负责支持虚存系统的请页操作。与交换进程一样,页守护进程也是内核进程。

syslogd守护进程可用于任何为操作人员记录系统消息的程序中。可以在一台实际的控制台上打印这些消息,也可将它们写到一个文件中。
sendmail是标准邮递守护进程。
update程序定期将内核缓存中的内容写到硬盘上(通常是每隔30秒)。为了做到这一点,该程序每隔 3 0秒调用sync(2)函数一次。
cron守护进程在指定的日期和时间执行指定的命令。许多系统管理任务是由 cron定期地使相关程序执行而得以实现的。
inetd守护进程,它监听系统的网络界面,以输入对各种网络服务器的请求。
lpd处理对系统提出的各个打印请求。

注意,所有守护进程都以超级用户(用户ID为0)的优先权运行。没有一个守护进程具有控制终端——终端名称设置为问号(?)、终端前台进程组ID设置为-1。缺少控制终端可能是守护进程调用了setsid的结果。除update以外的所有守护进程都是进程组的首进程,对话期的首进程,而且是这些进程组和对话期中的唯一进程。update是它所在进程组(37)和对话期(37)中的唯一进程,但是该进程组的首进程(可能也是该对话期的首进程)已经终止。最后,应当引起注意的是所有这些精灵进程的父进程都是init进程。

Daemon的分类

分类方式一:按照“是否可以独立启动”分类

stand alone类型的daemon
这种类型的daemon可以自行启动,启动之后可以常驻内存,直到手动关闭该daemon才释放资源。
最大的优点是响应速度快,多用于能够随时接受远程请求的服务,如WWW的daemon(httpd)、FTP的daemon(vsftpd)等。

由super daemon管理的daemon
这种类型的daemon由super daemon统一管理,当请求到来时,由super daemon启动请求的服务,请求完成后便释放内存资源。
早期的super daemon是inetd,后来被xinetd替代了。
注意:super daemon本身是一个stand alone的服务,因为它需要管理后续的其他服务,所以它自己本身当然需要常驻内存中。

两者的区别:
stand alone类型的daemon可以自行启动,无需依赖其他daemon;而super daemon管理的daemon必须借助super daemon来启动;
stand alone类型的daemon启动后便常驻内存,而被super daemon管理的daemon只有等到用户请求时才被加载进内存,并且在请求完成后便释放内存资源。由于后者每次请求到来的时候才被加载进内存,因此响应速度比stand alone型daemon要慢。但是它执行完就释放内存资源,因此更节约内存资源。

分类方式二:按照“请求到来时是否能够立即运行”分类

signal-control类型的daemon
这种类型的daemon当有请求到来时便能立即执行。

interval-control类型的daemon
这种类型的daemon会周期性地执行某项工作,因此它没有请求一说,它会周期性地读取配置文件,并执行配置文件中要求的功能。如crond、atd都属于interval-control类型的daemon。

Daemon的启动

服务启动脚本存放位置

Linux系统中有一个公认的目录用来存放服务启动脚本: ”/etc/init.d/“。即使有些Linux系统的服务启动脚本没有放在/etc/init.d/目录下,它也会设置连接文件到/etc/init.d/下的。

与daemon相关的目录介绍
/etc/init.d/
该目录存放所有stand alone型daemon的初始化脚本。
/etc/sysconfig/
该目录存放所有daemon的初始化配置文件。
/etc/xinetd.conf
该文件是super daemon的配置文件。
该文件将会加载/etc/xinetd.d/目录下的所有配置文件。
/etc/xinetd.d/
该目录存放所有被super daemon管理的daemon的配置文件。
daemon启动或关闭就在这些配置文件中配置。
/etc/
该目录存放各daemon各自的配置文件。
/var/lib/
该目录存放各daemon的数据库文件。
/var/run/
该目录记录各daemon的PID。

服务启动方式

stand alone型Daemon的启动方式

通过/etc/init.d/xxx启动
启动一个服务是一个繁琐的过程,你需要进行一系列启动前的操作,为了避免这些麻烦,服务提供商把这些繁琐的过程封装在一个shell srcipt中,我们只需执行一个shell script即可启动一个daemon。几乎所有的stand alone型daemon的启动脚本都放在/etc/init.d/下,所以我们只需执行/etc/init.d/xxx start即可启动xxx服务。

通过service命令启动
若每次启动一个命令都要写/etc/init.d/略微有些麻烦,service命令将其进行了封装,我们只要执行service xxx start/status/restart/stop即可开启/查看/重启/关闭xxx服务。

super daemon型Daemon的启动方式

step1:设置daemon的配置文件
每一个被super daemon管理的daemon都有一个配置文件,在/etc/xinetd.d/目录下。每个daemon的开启或关闭均在该daemon对应的配置文件中设置。

step2:启动super daemon
super daemon是一个stand alone型daemon,因此在daemon的配置文件设置好后可通过service xinetd start启动所有由super daemon管理的daemon。

简单小结:服务启动方式
(1)通用的启动方式:/etc/init.d/* {start|stop|status|restart}。
(2)部分系统特有的:service [service name] {start|stop|status|restart}
和 rc[service name] {start|stop|status|restart}。
例如重启crontab服务,分别用以上三种方式:
/etc/init.d/crond restart
service crond restart
rccrond restart

设置Daemon开启启动

Linux启动时可以选择有不同的开机等级,不同等级将会开启不同的系统服务。窗口界面的执行等级为level5,命令行的执行等级为level3.
我们可以用chkconfig命令来查看和设置开机启动的服务:

  • 查看chkconfig –list [指定服务的开机启动情况]
NetworkManager  0:off   1:off   2:off   3:off   4:off   5:off   6:off
acpid           0:off   1:off   2:off   3:off   4:off   5:off   6:off
aegis           0:off   1:off   2:on    3:on    4:on    5:on    6:off
anacron         0:off   1:off   2:off   3:off   4:off   5:off   6:off
atd             0:off   1:off   2:off   3:off   4:off   5:off   6:offxinetd based services:chargen-dgram:  offchargen-stream: offdaytime-dgram:  offdaytime-stream: off

我们可以看到,所有的服务被分成两块,一块是stand alone型的daemon,一块是被super daemon管理的daemon。我们可以发现,只有stand alone型的daemon才拥有执行等级。

  • chkconfig –level [0123456] [服务名称] [on/off]
chkconfig --level 3 redis on #将redis在level3情况下设为开机自启

设置成功之后可以看到,redis在level3下已经on:

[root@i]# chkconfig --list redis
redis           0:off   1:off   2:off   3:on    4:off   5:off   6:off

Daemon的配置

具体的某个daemon的配置

service rsync #service后为daemon的名字
{disable = yes #yes表示关闭此daemon,no表示开启此daemonsocket_type     = stream #stream表示使用TCP、dgram表示使用UDP、raw表示直接与IP交互wait            = nouser            = root #以什么用户的身份启动这个daemonserver          = /usr/bin/rsync #这个daemon的启动程序server_args     = --daemon #启动时所需的参数log_on_failure  += USERID #登录失败时需要记录用户
}

=:表示将某个参数设为等号右侧的值,若先前设置中已设置过该参数,则直接覆盖
+=:表示保留先前设置的这个参数,再给这个参数增加个值。
-和-=的含义同上。

super daemon的防火墙配置

由于受super daemon管理的daemon的请求都首先需要经过super daemon,因此super daemon可以充当防火墙的角色,拒绝一些不安全的请求。
super daemon提供了两种防火墙机制,第一种方式提供较多详细的安全设置,而第二种方式只能阻挡或允许指定的IP,具体见下:

方式一:使用首super daemon管理的daemon的配置文件实现防火墙机制
在某个具体的daemon配置文件中添加如下参数,即可为daemon配置防火墙:

instance=数字/UNLIMITED:设置该daemon能够承受的最大连接数。
per_source=数字/UNLIMITED:每个IP的最大连接数。
Cps=数字1 数字2:该daemon在一秒内的连接数超过数字1,则暂时关闭该daemon数字2的秒数。
log_on_success/failure=PID/HOST/USERID/EXIT/DURATION:当登录成功/失败时记录的信息。HOST:连接者的IP、EXIT:离开时间、DURATION:为该用户服务的时间。
redirect=IP:将用户的请求转至指定服务器。
bind=IP:允许用户用哪个IP访问本服务。
only_from=[0.0.0.0,192.168.1.0:24]:只允许指定IP的用户访问。0.0.0.0表示允许所有用户,192.168.1.0:24表示只允许192.168.1.1-192.168.1.255之间的用户访问。
access_time=00:00-12:00:只允许该时间段内访问。

方式二:使用xinetd提供的/etc/hosts.allow和/etc/hosts.deny实现防火墙机制
/etc/hosts.allow
我们可以在该文件中设置允许访问的IP
/etc/hosts.deny
我们可以在该文件中设置不允许访问的IP

Daemon程序设计

为什么daemon进程需要特殊的编写步骤?
daemon进程和普通进程不一样吗?为什么要单独提出如何编写daemon进程呢?
不知道你是否有过这样的经历,在Linux上面打开一个terminal,输入编译命令进行编译,编译的时间可能比较长,这时候你不小心关闭了这个terminal,编译就中断了。因为编译脚本是作为当前terminal的一个子进程来执行的,当terminal退出后,子进程也就退出了。而作为daemon进程,我们希望一旦启动就能在后台一直运行,不会随着terminal的退出而结束。

那么如何能做到这一点呢?有人说用下面的命令行吗?

make &

让编译命令make到后台执行,这样只是造成了make在后台一直运行的假象,它依然没有脱离和terminal之间的父子关系;当terminal退出后,make依然会退出。所以针对daemon进程就要用特殊的步骤来编写,以保证在terminal中执行后,即使terminal退出,daemon进程仍然在后台运行。

设计步骤

(1)程序运行后调用fork,并让父进程退出。子进程获得一个新的进程ID,但继承了父进程的进程组ID。
(2)调用setsid创建一个新的session,使自己成为新session和新进程组的leader,并使进程没有控制终端(tty)。
(3)设置文件创建mask为0,避免创建文件时权限的影响。
(4)关闭不需要的打开文件描述符。因为Daemon程序在后台执行,不需要于终端交互,通常就关闭STDIN、STDOUT和STDERR。其它根据实际情况处理。
(5)Daemon无法输出信息,可以使用SYSLOG或自己的日志系统进行日志处理。(可选)
(6)编写管理Daemon的SHELL脚本,使用service对Daemon进行管理和监控。(可选)

  • APUE中的方法
#include "apue.h"
#include <syslog.h>
#include <fcntl.h>
#include <sys/resource.h>void daemonize(const char *cmd){int i, fd0, fd1, fd2;pid_t pid;struct rlimit rl;struct sigaction sa;/* * Clear file creation mask. */umask(0);/* * 因为我们从shell创建的daemon子进程,* 所以daemon子进程会继承shell的umask,* 如果不清除的话,会导致daemon进程创建文件时屏蔽某些权限。*//* * Get maximum number of file descriptors. */if (getrlimit(RLIMIT_NOFILE, &rl) < 0)err_quit("%s: can't get file limit", cmd);/* * Become a session leader to lose controlling TTY. */if ((pid = fork()) < 0)/* * fork后让父进程退出,子进程获得新的pid,肯定不为进程组组长,这是setsid前提。*/err_quit("%s: can't fork", cmd);else if (pid != 0) /* parent */exit(0);setsid();/* * 调用setsid来创建新的进程会话。这使得daemon进程成为会话首进程,脱离和terminal的关联。*//* * Ensure future opens won't allocate controlling TTYs. */sa.sa_handler = SIG_IGN;sigemptyset(&sa.sa_mask);sa.sa_flags = 0;if (sigaction(SIGHUP, &sa, NULL) < 0)err_quit("%s: can't ignore SIGHUP", cmd);if ((pid = fork()) < 0)/* * 最好在这里再次fork。* 这样使得daemon进程不再是会话首进程,那么永远没有机会获得控制终端。* 如果这里不fork的话,会话首进程依然可能打开控制终端。*/err_quit("%s: can't fork", cmd);else if (pid != 0) /* parent */exit(0);/* * Change the current working directory to the root so * we won't prevent file systems from being unmounted. */if (chdir("/") < 0)/* * 将当前工作目录切换到根目录。* 父进程继承过来的当前目录可能mount在一个文件系统上,* 如果不切换到根目录,那么这个文件系统不允许unmount。*/err_quit("%s: can't change directory to /", cmd);/* * Close all open file descriptors. */if (rl.rlim_max == RLIM_INFINITY)rl.rlim_max = 1024;for (i = 0; i < rl.rlim_max; i++)close(i);/* * 在子进程中关闭从父进程中继承过来的那些不需要的文件描述符。* 可以通过_SC_OPEN_MAX来判断最高文件描述符(不是很必须). *//* * Attach file descriptors 0, 1, and 2 to /dev/null. */fd0 = open("/dev/null", O_RDWR);fd1 = dup(0);fd2 = dup(0);   /* * 打开/dev/null复制到0,1,2,因为dameon进程已经和terminal脱离了,* 所以需要重新定向标准输入,标准输出和标准错误(不是很必须). *//* * Initialize the log file. */openlog(cmd, LOG_CONS, LOG_DAEMON);if (fd0 != 0 || fd1 != 1 || fd2 != 2) {syslog(LOG_ERR, "unexpected file descriptors %d %d %d",fd0, fd1, fd2);exit(1);}
}

利用系统库函数daemon()创建daemon进程

Linux系统还专门提供了一个用来创建daemon进程的系统函数:

int daemon(int nochdir, int noclose);

返回值:int nochdir 是否改变路径,
int noclose ,是否关闭终端
一般两个参数的值设置为零,默认不改变路径,并且关闭终端。原因:

当 nochdir为零时,当前目录变为根目录,否则不变;#include <unistd.h> int daemon(int nochdir, int noclose);

当 noclose为零时,标准输入、标准输出和错误输出重导向为/dev/null,也就是不输出任何信息,否则照样输出。

deamon()调用了fork(),如果fork成功,那么父进程就调用_exit(2)退出,所以看到的错误信息全部是子进程产生的。如果成功函数返回0,否则返回-1并设置errno。

#include <unistd.h>
#include <stdlib.h>int main(void)
{if(daemon(0,0) == -1)exit(EXIT_FAILURE);while(1){sleep(60);}return 0;
}

参考资料:https://blog.csdn.net/woxiaohahaa/article/details/53487602?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-5.nonecase&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-5.nonecase
https://blog.csdn.net/prettyshuang/article/details/38442517?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-3.nonecase&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-3.nonecase

linux daemon(守护进程)相关推荐

  1. another mysql daemon,[守护进程详解及创建,daemon()使用

    一,守护进程概述 Linux Daemon(守护进程)是运行在后台的一种特殊进程.它独立于控制终端并且周期性地执行某种任务或等待处理某些发生的事件.它不需要用户输入就能运行而且提供某种服务,不是对整个 ...

  2. Linux系统守护进程详解

    文中有不对或者有不清楚的地方,请大家告诉我,谢谢!   Linux系统守护进程详解 不要关闭下面这几个服务: acpid, haldaemon, messagebus, klogd, network, ...

  3. 【Linux】- 守护进程的启动方法

    转自:Linux 守护进程的启动方法 Linux中"守护进程"(daemon)就是一直在后台运行的进程(daemon). 本文介绍如何将一个 Web 应用,启动为守护进程. 一.问 ...

  4. 深入理解Linux操作系统守护进程的意义

    深入理解Linux操作系统守护进程的意义 Linux服务器在启动时需要启动很多系统服务,它们向本地和网络用户提供了Linux的系统功能接口,直接面向应用程序和用户.提供这些服务的程序是由运行在后台的守 ...

  5. Linux的守护进程

    Linux的守护进程: crontab –e –l –r /etc/cron.allow:将可以使用crontab的账号写入其中,若不在这个档案内的使用者则不可使用crontab: /etc/cron ...

  6. linux 安装守护进程supervisor

    linux的守护进程类似于windows的服务.linux通过supervisor创建守护进程. 1.安装supervisor sudo apt-get install supervisor -- u ...

  7. linux中Daemon守护进程编程

    守护进程,也就是通常说的Daemon进程,是Linux中的后台服务进程.它是一个生存期较长的进程,通常独立于控制终端并且周期性地执行某种任务或等待处理某些发生的事件.守护进程常常在系统引导装入时启动, ...

  8. Linux下守护进程(daemon)的实现

    文章目录 守护进程 守护进程的创建 守护进程的实现 守护进程 守护进程是一种特殊的孤儿进程,父进程是一号init进程,运行在后台,与终端和登陆会话脱离关系,不受影响. 守护进程通常系统引导的时候启动, ...

  9. 【Linux】守护进程( Daemon)的定义,作用,创建流程

    守护进程( Daemon) 守护进程( Daemon) 1.定义 2.作用 3.创建流程 4.实例 参考 守护进程( Daemon) 1.定义 守护进程是运行在后台的一种特殊进程,它独立于控制终端并且 ...

  10. linux下daemon守护进程的实现(以nginx代码为例)

    ngx_int_t ngx_daemon(ngx_log_t *log) {int fd;// 让init进程成为新产生进程的父进程:// 调用fork函数创建子进程后,使父进程立即退出.这样,产生的 ...

最新文章

  1. HTTP 协议中的 cookie
  2. (格式化字符串漏洞).fini.array劫持,使程序流程循环进行
  3. 漫谈单点登录(SSO)(淘宝天猫)(转载)
  4. JAVA学习-JAVA数组的使用示例
  5. [Python] 拉格朗日插值
  6. 吴恩达机器学习总结四:Octave语法
  7. 不用于mysql权限管理的24260_[MySQL Reference Manual] 24 MySQL sys框架
  8. Java instanceof用法
  9. 【干货】深度学习实验流程及PyTorch提供的解决方案
  10. 网页版WebRTC多人聊天Demo
  11. idea设置护眼主题
  12. mysql人脸数据库_人脸数据库汇总
  13. 机器学习与模式识别期末试题回忆
  14. markdown下载及基本语法
  15. donet使用linq
  16. 玩客云刷入armbian系统总结
  17. 电影级视觉特效插件:Red Giant VFX Suite for mac
  18. 信息系统项目管理师备考资料-第三版(4)
  19. 03教育与社会的发展
  20. pycharm alt+enter智能提示无法进行包导入

热门文章

  1. C++ template —— tuple(十三)
  2. 不要轻易当舔狗,除非你想当技术型舔狗
  3. linux+显卡超频软件,安装和使用GreenWithEnvy在Linux上超频Nvidia显卡
  4. XDOJ 363 输出快速排序递归算法隐含递归树的后序遍历序列 AC
  5. requireJS的使用
  6. AD转换(ADC0809)
  7. 用友金蝶 不同道路,殊途同归
  8. 计算机技术 食堂管理,食堂管理系统需求规格说明.doc
  9. 不要在寂寞的时候爱谁
  10. Mysql当前时间是否在4月活动时间范围内