linux服务端程序都需要提供7 * 24不间断的服务,如何保证工作进程一直不退出或者不被kill掉,常见的方法就是启动一个守护进程来检测工作进程的状态,如果发现工作进程退出,就再fork一个出来。一般的实现见下面一段代码:
// 守护进程(父进程) int status; for ( ; ; ) { if ( 0 == ( pid = fork()) ) { // 工作进程(子进程) run(); } waitpid(-1, &status, 0); if (WIFEXITED(status)) if (WEXITSTATUS(status) == 0) exit(0); if (WIFSIGNALED(status)) { switch (WTERMSIG(status)) { case SIGKILL: exit(0); break; case SIGINT: case SIGTERM: exit(1); default: break; } } }
守护进程fork出工作进程之后,就阻塞在waitpid系统调用,等待工作进程的退出,waitpid返回之后,根据status选择继续fork工作进程还是退出守护进程。status为int型变量,但只用到了低16位(见struct wait),0-6位表示使子进程退出的信号(可以通过 $kill -l 查看信号的值),8-15位表示子进程退出时的返回码(exit或者return的值)。
struct wait{ # if __BYTE_ORDER == __LITTLE_ENDIAN unsigned int __w_termsig:7; /* Terminating signal. */ unsigned int __w_coredump:1; /* Set if dumped core. */ unsigned int __w_retcode:8; /* Return code if exited normally. */ unsigned int:16; # endif /* Little endian. */ };判断status的状态可以通过下面的宏完成:
WIFEXITED(status) //子进程调用exit()或者从main return退出时为true; WEXITSTATUS(status) //在WIFEXITED为true时,表示exit()或return的返回码; WIFSIGNALED(status) //子进程被信号终止时为true; WTERMSIG(status) //在WIFSIGNALED为true时,表示终止子进程信号的值;
宏的定义如下:
/* If WIFEXITED(STATUS), the low-order 8 bits of the status. */ #define __WEXITSTATUS(status) (((status) & 0xff00) >> 8) /* If WIFSIGNALED(STATUS), the terminating signal. */ #define __WTERMSIG(status) ((status) & 0x7f) /* Nonzero if STATUS indicates normal termination. */ #define __WIFEXITED(status) (__WTERMSIG(status) == 0) /* Nonzero if STATUS indicates termination by a signal. */ #define __WIFSIGNALED(status) \ (((signed char) (((status) & 0x7f) + 1) >> 1) > 0)
所以根据waitpid返回的status,守护进程可以清楚地知道工作进程的死因,但上面的程序有两个问题:
1. 对SIGKILL, SIGINT, SIGTERM信号,守护进程直接退出了,没有fork工作进程出来;
2. 守护进程被kill掉了,工作进程就只能裸奔了。
对于第一个问题:SIGKILL有可能是人为($kill -9 pid)发出的,也有可能是工作进程占用内存过多,被OOM掉了(关于OOM参见这里),都不是我们想要的结果,所以工作进程被SIGKILL掉,守护进程一定要将其重启。SIGINT是 CTRL+C 发出的(非daemon模式下),SIGTERM是 $killall servicename(或者 $kill pid)发出的,这两个信号都是在结束进程的时候用到,这个时候工作进程应该捕获被处理这两个信号,正常地退出(return 0;)。而守护进程只有在工作进程正常退出的情况下才完成自己的使命,否则(工作进程被其他信号结束掉,如SIGABRT, SIGKILL, SIGSEGV)重启工作进程。所以守护进程和工作进程的实现应该是下面的代码逻辑:
// 守护进程(父进程) int status; for ( ; ; ) { if ( 0 == ( pid = fork()) ) { // 工作进程(子进程) run(); //信号处理函数signal_handler if (sig == SIGTERM || sig == SIGINT) { destroy(); return 0; } } waitpid(-1, &status, 0); if (WIFEXITED(status) && (WEXITSTATUS(status) == 0)) exit(0); }对于第二个问题:守护进程的监控可以用daemontools工具集中的supervise来监控,也可以自己实现,但是不能只是通过另外一个应用程序去做,因为做守护的进程自身也需要被守护,如此循环解决不了问题。这个时候就要借助于linux系统的init进程了,因为init进程是不能被信号kill掉的(强大到无视SIGKILL)。
The only signals that can be sent task number one, the init process, are those for which init has explicitly installed signal handlers. This is done to assure the system is not brought down accidentally.
所以让init进程来守护我们的应用程序是最可靠的,看看supervise的作法:
在/etc/inittab中添加如下一行:
SV1:23:respawn:/usr/local/bin/svscanboot
每行用“:”分隔开为4个部分:
id - 该行的标识,自定义的名称SV1。
runlevels - 该行为应该发生的运行级的列表,这里在level 2和level 3下运行。
action - 应发生的行为,respawn表示init应该监视这个进程,即使其结束后也应该被重新启动。
process - 应由init启动的程序的路径。
修改完成后,可以通过$kill -HUP 1 来立刻生效。
解决了上面两个问题,守护进程和工作进程提供7 * 24小时的运行才是有保证的。Have fun!
相关推荐
编写 Linux 守护进程 Linux/Unix 守护进程是指在后台运行的进程,不与控制终端交互,独立于控制终端的输入/输出操作。编写 Linux 守护进程需要了解...通过遵循这八条经验,可以编写一个稳定、可靠的 Linux 守护进程。
《编写Linux守护进程》这篇文献主要探讨了如何在Linux操作系统中创建和管理守护进程,这是一种在后台运行且独立于控制终端的进程,常用于提供系统服务,如HTTP服务器、打印服务等。守护进程的主要特点包括: 1. **...
本篇文章提供一个软件实现守护进程的办法,原理就是udp通信,单独写个守护进程程序,专门负责检测主程序是否存在,不存在则启动。主程序只需要启动live类监听端口,收到hello就回复ok就行。 为了使得兼容任意程序,...
### Linux系统下守护进程编程方法 #### 一、守护进程概览 守护进程(Daemons)是Linux系统中一类特殊的服务程序,它们通常在后台运行,没有控制终端,也不依赖于任何登录Shell。守护进程的设计目标是高可靠性,...
### Linux守护进程详解 #### 一、什么是守护进程(Daemon) 在Linux系统中,守护进程是一种后台服务程序,它们在启动后与控制终端脱离,并在后台持续运行,为用户提供服务或者执行特定的任务。守护进程是操作系统...
要使一个守护进程在系统启动时自动启动,需要将其配置为系统服务,并将其添加到启动脚本中。本教程将详细介绍在Debian、Red Hat和Ubuntu系统下,如何编写和配置守护进程,使其随系统启动而启动。 首先,我们需要...
Linux守护进程,或称为守护程序或精灵进程,是Linux操作系统中的关键组成部分,它们在后台运行,没有控制终端,且通常以超级用户权限运行。守护进程的主要任务是提供系统服务,如网络服务(如HTTP服务器httpd)、...
守护进程(Daemon)是Linux操作系统中的一个重要组成部分,它们在后台运行,不与用户交互,主要用于提供系统服务。例如,网络服务、时间同步、打印服务等都由守护进程来执行。守护进程能够独立于控制终端运行,并且...
### Linux守护进程的研究 #### 摘要与背景 本文主要探讨了Linux系统下的守护进程(Daemons)的概念、特点及其启动方式,并给出了一个具体的C语言实现案例。守护进程是Linux系统中非常重要的一种进程类型,它运行在...
本文将深入探讨如何利用Delphi编程语言来创建一个守护进程,该进程能够监控并自动重启指定的应用程序。 Delphi,一种基于Object Pascal的强大的集成开发环境,以其高效和灵活的特性深受程序员喜爱。在Windows平台上...
这个简单的示例展示了如何创建一个基本的守护进程,但实际上,守护进程通常会处理更多复杂的逻辑,例如监听网络端口、管理配置文件、记录日志等。在实际应用中,你可能会使用系统提供的工具如`daemonize`或编写更...
在IT行业中,守护进程...总的来说,通过`serverd.c`和`client1.c`这两个示例,我们可以深入理解Linux守护进程的创建和Socket通信的基本原理,这对于理解网络服务的底层运作和开发自己的服务程序是非常有价值的。
"Linux系统下守护进程编程方法" ...Linux系统下守护进程编程方法需要考虑到进程的创建、进程的继承、守护进程的启动方式、守护进程的创建步骤等多个方面,编写一个可靠的守护进程程序需要考虑到这些问题。
Linux守护进程,也称为守护程序,是Linux操作系统中一类特殊进程,它们在后台运行,与任何终端或登录Shell无关,通常用于提供系统服务,如打印服务、任务调度、邮件服务等。守护进程的名字通常以“d”结尾,比如atd...
在Linux操作系统中,守护进程(Daemon)是系统后台运行的重要组成部分,它们不与用户界面直接交互,而是持续运行以提供服务或执行特定任务。守护进程的生命周期长,通常在系统启动时启动,并在系统关闭时终止。由于...
总结来说,"msq.c.tar.gz_linux 守护进程_msq"这个压缩包文件提供的可能是关于Linux守护进程和消息队列的编程实例,通过阅读和理解"msq.c"的代码,开发者可以学习到如何在实际项目中利用这两种机制实现高效、安全的...
在Unix/Linux环境中,POS(Point of Sale)系统是用于商业交易处理的重要软件,它通常包含一个前端客户端和一个后台守护进程。"POS.rar_linux 守护进程_pos"这个标题暗示了我们正在处理一个专为Linux设计的POS系统,...
`supervisord`是一个用Python编写的进程控制系统和应用监控工具,能够管理多个进程,提供详细的日志记录和进程状态监控,并且支持自定义监控间隔和重启策略。 了解了进程监控和进程守护程序的功能和作用后,我们...
标题"守护进程(互相监听)"可能指的是两个守护进程之间进行通信和监控的场景,这种设计可以确保即使一个守护进程出现问题,另一个仍然能够检测到并采取相应措施,提高系统的稳定性和可靠性。这种互相监听的机制常见...
标题“c#实现的守护进程,包含代码”意味着我们将探讨如何使用C#编写一个能够监控并保证某个特定进程始终运行的程序。这种程序可能被设计为Windows服务,以便在操作系统启动时自动运行,并在进程意外终止时重新启动...