简介

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

创建守护进程

  • 终端(terminal)是计算机用于文本输入与显示的交互界面。
  • 前台任务(foreground job)是独占命令行窗口的任务,只有运行完了或者手动中止该任务,才能执行其他命令。
  • 后台任务(background job),与前台任务相对应,在多任务系统中,有一些任务在运行的时候,并不需要与用户交互。它们通常在不打扰用户其它工作的时候默默地执行(此时可以输入其他的命令)。后台任务继承当前session(对话,就是终端窗口)的标准输出(stdout)和标准错误(stderr)。因此,后台任务的所有输出依然会同步地在命令行下显示。不再继承当前session的标准输入(stdin)。你无法向这个任务输入指令了。如果它试图读取标准输入,就会暂停执行(halt)。
  • 守护进程(daemon)是指在UNIX或其他多任务操作系统中在后台执行的电脑程序,并不会接受电脑用户的直接操控。此类程序会被以进程的形式初始化。守护进程程序的名称通常以字母“d”结尾:例如,syslogd就是指管理系统日志的守护进程。用户退出session之后,“后台任务是否会继续执行”是判定这一任务是否为“守护进程”的依据。

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

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

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

  1. 用户准备退出 session
  2. 系统向该 session 发出SIGHUP信号
  3. session 将SIGHUP信号发给所有子进程
  4. 子进程收到SIGHUP信号后,自动退出

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

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

$ node server.js &
$ disown

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

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

$ node server.js > stdout.txt 2> stderr.txt < /dev/null &$ disown

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

注:
/dev/null文件的作用
这是一个无底洞,任何东西都可以定向到这里,但是却无法打开。
所以一般很大的stdou和stderr当你不关心的时候可以利用stdout和stderr定向到这里

$ ./command.sh >/dev/null 2>&1

更简便地创建守护进程: nohup 命令

$ nohup node server.js &

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

  • 阻止SIGHUP信号发到这个进程。
  • 关闭标准输入。该进程不再能够接收任何输入,即使运行在前台。
  • 重定向标准输出和标准错误到文件nohup.out。

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

总结

守护进程创建方法:

方法一:

$ node server.js > stdout.txt 2> stderr.txt < /dev/null &
$ disown

方法二:

$ node server.js > stdout.txt 2> stderr.txt < /dev/null 
^z
$ bg
$ disown

方法三:

$ nohup node server.js &

命令总结

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

一、&

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

# 每10s在后台执行一次test.sh脚本
$ watch -n 10shtest.sh & 

二、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),然后执行

$ kill %num

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

$ kill pid

前台进程的终止:Ctrl+c

七、nohup

如果想让程序即使在关闭当前的终端后也始终在后台执行(之前的&做不到),需要使用nohup命令。
nohup命令可以在你退出帐户/关闭终端之后继续运行相应的进程。
关闭终端后,在另一个终端jobs已经无法看到后台跑的程序了,此时利用ps(进程查看命令)查看进程。

ps -aux | grep "test.sh"
#ps选项说明: a:显示所有程序 u:以用户为主的格式来显示 x:显示所有程序,不以终端机来区分