Linux系统中的守护进程讲解

Linux系统中的守护进程讲解,第1张

守护进程daemon,是生存期较长的一种进程。它们常常在系统自举时启动,仅在系统关闭时才终止。因为它们没有控制终端,所以说它们是在后台运行的。UNIX系统有很多守护进程,它们执行日常事务活动。

1、系吵物统自举

自举(bootstrapping)一词来自于人都是靠自身的自举机构站立起来的这一思想。计算机必须具备自举能力将自己所有的元件激活,以便能完成加载 *** 作系统这一目的,然后再由 *** 作系统承担起那些单靠自举代码无法完成的更复杂的任务。

自举只有两个功能:加电自检和磁盘引导。

加电自检:当我们按下计算机电源开关时,头几秒钟机器似乎什么反应也没有,其实,这时的计算机正在进行加电自检,以断定它的所有元件都在正确地工作。如果某个元件有故障,显示器上就会出现报警提示信息(如果显示器也不能正常工作,则以一串嘟嘟声来报警)。由于大多数计算机工作非常可靠,加电自检报警非常罕见。

磁盘引导:查找装有 *** 作系统的磁盘驱动器。从磁盘加载 *** 作系统的原因有二,一是 *** 作系统升级简单容易,二是使用户拥有选择 *** 作系统的自由。

当加电自检和磁盘引裂唯导完成时,自举 *** 作就启动一个读写 *** 作系统文件和将它们复制到随机存储器中的过程,此时的机器才是真正意义上的计算机。计算机的启动可以有冷启动和热启动两种方式 ,它们之间的差别是热启动不进行机器的自检(机器本身配置的检查与测试),当计算机在使用过程中由于某些原因造成死机时,可以对计算机进行热启动处理。

2、守护进程的概念

通过ps axj命令可以查看到守护进程:

参数a表示不仅列当前用户的进程,也列出所有其他用户的进程,参数x表示不仅列有控制终端的进程,也列出所有无控制终端的进程,参数j表示列出与作业控制相关的信息。

代码如下:PPID PID PGID SID TTY TPGID STAT UID TIME COMMAND 0 1 1 1 ? -1 Ss 0 0:01 /sbin/init 0 2 0 0 ? -1 S<0 0:00 [kthreadd] 2 3 0 0 ? -1 S<0 0:00 [migration/0] 2 4 0 0 ? -1 S<0 0:00 [ksoftirqd/0]... 1 2373 2373 2373 ? -1 S<s 0 0:00 /sbin/udevd --daemon... 1 4680 4680 4680 ? -1 Ss 0 0:00 /usr/sbin/acpid -c /etc... 1 4808 4808 4808 ? -1 Ss 102 0:00 /sbin/syslogd -u syslog...

凡是TPGID一栏写着-1的升源液都是没有控制终端的进程,也就是守护进程。在COMMAND一列用[]括起来的名字表示内核线程,这些线程在内核里创建,没有用户空间代码,因此没有程序文件名和命令行,通常采用以k开头的名字,表示Kernel。init进程我们已经很熟悉了,udevd负责维护/dev目录下的设备文件,acpid负责电源管理,syslogd负责维护/var/log下的日志文件,可以看出,守护进程通常采用以d结尾的`名字,表示Daemon。 创建守护进程最关键的一步是调用setsid函数创建一个新的Session,并成为Session Leader。 例子: C/C++ Code复制内容到剪贴板 void daemonize(void) { pid_t pidprintf("into deamonizen")if (pid=fork() <0) { perror("fork")exit(1)} else if (pid !=0) { exit(0)} setsid()if (chdir("/") <0) { perror("chdir")exit(1)} close(0)open("/dev/null", O_RDWR)dup2(0, 1)dup2(0, 2)printf("out deamonizen")}

3、编写守护进程 在编写守护进程程序时,需遵循一些基本规则:

(1)首先要做的是调用umask将文件模式创建屏蔽字设置为0。

(2)调用fork,然后使父进程退出。

(3)调用setsid以创建一个新会话。

(4)将当前工作目录更改为根目录。

(5)关闭不再需要的文件描述符。

(6)某些守护进程打开/dev/null使其具有文件描述符0、1和2,任何一个试图读标准输入、写标准输出或标准出错的库例程都不会产生任何效果。 与守护进程有关的一个问题是如何处理出错消息,需要有一个集中的守护进程出错记录设施,这就是syslogd进程。

4、守护进程惯例 为了正常运作,某些守护进程实现为单实例的,有就是在任一时刻只运行该守护进程的一个副本。文件锁和记录锁机制是一种方法的基础,该方法用来保证一个守护进程只有一个副本在运行。

在UNIX系统中,守护进程遵循下列公共惯例:

(1)若守护进程使用锁文件,那么该文件通常存放在/var/run目录中。锁文件的名字通常是name.pid,name是该守护进程或服务的名字。

(2)若守护进程支持配置选项,那么配置文件通常存放在/etc目录中。配置文件的名字通常是name.conf。

(3)守护进程可用命令行启动,但通常它们是由系统初始化脚本启动的。

(4)若一守护进程有一配置文件,那么当该守护进程启动时,它读该文件,但在此之后一般就不会再查看它。

1、守护进程,也就是通常说的Daemon进程,是Linux中的后台服务进程。它是一个生存期较长的进程,通常独立于控制终端并且周期性地执行某种任务或等待处理某些发生的事件。如果想让某个进程不因为用户或终端或其他地变化而受到影响,那么就必须把这个进程变成一个守护进程。

2、创建守护进程步骤

1)创建子进程,父进程举液退出

之后的所有工作都在子进程中完成,而用户在Shell终端里则可以执行其他命令,从而在形式上做到了与控制终端的脱离。

在Linux中父进程先于子进程退出会造成子进程成为孤儿进程,而每当系统发现一个孤儿进程时,就会自动由1号进程(init)收养它,这样,原先的子进程就会变成init进程的子进程。

2)在子进程中创建新会话

进程组:是一个或多个进程的集合。进程组有进程组ID来唯一标识。除了进程号(PID)之外,进程组ID也是一个进程的必备属性。每个进程组都有一个组长进程,其组长进程的进程号等于进程组ID。且该进程组ID不会因组长进程的退出而受到影响。

会话周期:会话期是一个或多个进程组的集合。通常,一个会话开始于用户登录,终止于用户退出,在此期间该用户运行的所有进程都属于这个会话期。

(1)pid_t setsid(void)

setsid() creates a new session if the calling process is not a process group leader. The calling process will be the only process in this new process group and in this new session.

setsid函数用于创建一个新的会话,并担任该会话组的组长。调用setsid有下面的3个作用:

① 让进程摆脱原会话的控制

② 让进程摆脱丛答猜原进程组的控制

③ 让进程摆脱原控制终端的控制

有以下三个结果:

(a)成为新会话的首进程

(b)成为一个新进程组的组长进程

(c)没有控制终端。

有些人建议在此时再次调用fork,并使父进程终止。第二个子进程作为守护进程继续运行。这样就保证了该守护进程不是会话首进程。

setsid函数能够使进程完全独立出来,从而摆脱其他进程的控制。

setsid()调用成功后,进程成为新的会话组长和新的进程组长,并与原来的登录会话和进程组脱离。由于会话过程对控制终端的独占性,进程同时与控制终端脱离。 子进程可以自己组成一个新的进程组,即调用setpgrp()与原进程组脱离关系,产生一个新的进程组,进程组号与它的进程号相同.这样,父进程退出运行后就不会影响子进程的当前运行.

3)改变当前目录为根目录

使用fork创建的子进程继承了父进程的当渗型前工作目录;进程活动时,其工作目录所在的文件系统不能卸下。通常的做法是让"/"作为守护进程的当前工作目录,也可以是其他目录,如/tmp,使用chdir。

4)重设文件权限掩码

文件权限掩码是指屏蔽掉文件权限中的对应位。比如,有个文件权限掩码是050,它就屏蔽了文件组拥有者的可读与可执行权限。mask = mask &~050

通常,把文件权限掩码设置为0,umask(0)。

5)关闭文件描述符

用fork函数新建的子进程会从父进程那里继承已经打开了的文件描述符。这些被打开的文件可能永远不会被守护进程读写,但它们一样消耗系统资源,而且可能导致所在的文件系统无法卸下。

在上面的第二步之后,守护进程已经与所属的控制终端失去了联系。因此从终端输入的字符不可能达到守护进程,守护进程中用常规方法(如printf)输出的字符也不可能在终端上显示出来。所以,文件描述符为0、1和2 的3个文件(常说的输入、输出和报错)已经失去了存在的价值,也应被关闭。

for(i=0i<MAXFILEi++)

close(i)

6)守护进程退出处理

当用户需要外部停止守护进程运行时,往往会使用 kill命令停止该守护进程。所以,守护进程中需要编码来实现kill发出的signal信号处理,达到进程的正常退出。

signal(SIGTERM, sigterm_handler)

void sigterm_handler(int arg)

{

_running = 0

}

7)处理SIGCHLD信号

处理SIGCHLD信号并不是必须的。但对于某些进程,特别是服务器进程往往在请求到来时生成子进程处理请求。如果父进程不等待子进程结束,子进程将成为僵尸进程(zombie)从而占用系统资源。如果父进程等待子进程结束,将增加父进程的负担,影响服务器进程的并发性能。在Linux下可以简单地将 SIGCHLD信号的 *** 作设为SIG_IGN。

signal(SIGCHLD,SIG_IGN)

这样,内核在子进程结束时不会产生僵尸进程。

在Linux服务器实际应用中,经常会有需要长时间执行的任务。这类任务若在前台运行,用户无法进行其他 *** 作或者断开与服务器的连接,否则任务将被中止。此时适合使用守护进程。为了使用守护进程,需要了解Linux前台、后台、守护进程的概念与使用,本文将对此进行讲解。

可以看出,”后台任务”与”前台任务”的重要区别: 是否继承标准输入 。所以扒饥,执行后台任务的同时,用户还可以输入其他命令。

为了理解守护任务为何在结束session时也不退出,需要先了解Linux下退出session时发生的 *** 作。

Session退出时,linux系统设计如下:

前台任务会随着session的退出而退出是因为它收到了 SIGHUP信号

后台任务是否会受到SIGNUP信号,取决于shell的 huponexit 参数。可以通过 $ shopt | grep huponexit 查看该参数的值。大多数Linux系统,这个参数默认关闭(off)。因此,session退出的时候,不会把SIGHUP信号发给”后台任务”,即此时的后台任务是守护进程,但这显然不够安全。并不保险,因为有的系统的 huponexit 参数可能是打开的(on)状态。

更保险的方法是使用 disown命令。它可以将指定任务从”后台任务”列表(jobs命令的返回结果)之中移除 。一个”后台任务”只要不在这个列表之中,session 就肯定不会向它发出SIGHUP信号。

执行上面的命令以后, server.js 进程就被移出了”后台任务”列表。你可以执行 jobs 命令验证,输出结果里面,不会有这个进程。

但是,这样还存在问题。因为 ”后台任务”的标准 I/O 继承自当前 session, disown 命令并没有改变这一点 。一旦”后台任务”读写标准 I/O,就会发现它已经不存在了,所以就 报错终止执行 。 为了解决这个问题,需要对”后台任务”的 标准 I/O 进行重定向

这样基本上就没有问题了。

注:

/dev/null 文件的作用

这是一个无底洞,任何东西都可以定向到这里,但是却无法打开。

所以一般很大的stdou和stderr当你不关心的时候可以利用stdout和stderr定向到这里

nohup命令对server.js进程做了三件事。

阻止SIGHUP信号发到这个进程。

关闭标准输入。该进程不再能够接收任何输入,即使运行在前台。

重定向标准输出和标准枣此兆错误到文件nohup.out。

也就是说,nohup命令实际上将子进程与它所在的 session 分离了。 注意,nohup命令不会自动把进程变为”后台任务”,所以必须加上&符号

守护进程创建方法:

方法一:

方法二:

方法三:

fg、bg、jobs、&、nohup、ctrl+z、ctrl+c 命令

一、&

加在一个命令的最后,可以把这个命令放到后台执行,如:

二、ctrl + z

可以将一个正在前台执行的命令放到后台,并且处于暂停状态。

CTRL+Z 和 CTRL+C的对比

CTRL+Z 和 CTRL+C 都是中断命令,但是他们的作用却不一样.

CTRL+C 是强制中断程序的执行,而 CTRL+Z 的是将任务中断,但是此任务并没有结束,仍然在进程中,只是维持挂起的状态,用户可以使用 fg/bg *** 作继续前台或后台的任务。

三、jobs

查看当前有多少在后台运行的进程

jobs -l选项可显示所有任务的PID,jobs的状态可以是running, stopped, Terminated。但是如果任务被终止了(kill),shell 从当前的shell环境已知的列表中删除任务的进程标识。

四、fg

将后台中的命令调至前台继续运行。如果后台中有多个命令,可以用 fg %jobnumber (jobnumber是命令编号,凳租不是进程号)将选中的命令调出。

五、bg

将一个在后台暂停的命令,变成在后台继续执行。

如果后台中有多个命令,可以用 bg %jobnumber 将选中的命令调出。

六、kill

方法1:通过jobs命令查看job号(假设为num),然后执行

方法2:通过ps命令查看job的进程号(PID,假设为pid),然后执行

前台进程的终止:Ctrl+c

七、nohup

如果想让程序即使在关闭当前的终端后也始终在后台执行(之前的&做不到),需要使用nohup命令。

nohup命令可以在你退出帐户/关闭终端之后继续运行相应的进程。

关闭终端后,在另一个终端jobs已经无法看到后台跑的程序了,此时利用ps(进程查看命令)查看进程。

http://m.2cto.com/os/201301/185701.html

http://www.cnblogs.com/kaituorensheng/p/3980334.html

http://m.blog.csdn.net/article/details?id=50766752


欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/yw/12256591.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-05-24
下一篇 2023-05-24

发表评论

登录后才能评论

评论列表(0条)

保存