http://blog.csdn.net/mr_jj_lian/article/details/7252222

守护进程

守护进程是生存期长的一种进程。它们独立于控制终端并且周期性的执行某种任务或等待处理某些发生的事件。他们常常在系统引导装入时启动,在系统关闭时终止。unix系统有很多守护进程,大多数服务器都是用守护进程实现的。比如,网络服务inetd、Web服务http等。同时,守护进程完成许多系统任务。比如,作业规划进程crond、打印进程lqd等。

这里主要说明守护进程的进程结构,以及如何编写守护进程程序。因为守护进程没有控制终端,所以我们还要介绍在守护进程运行时错误输出的方法。

守护进程及其特性

守护进程最重要的特性是后台运行。在这一点上,DOS下的常驻内存程序TSR与之相似。

其次,守护进程必须与其运行前的环境隔离开来。这些环境包括未关闭的文件描述符、控制终端、会话和进程组、工作目录以及文件创建掩码等。这些环境通常是守护进程从执行它的父进程(特别是shell)中继承下来的。

最后,守护进程的启动方式有其特殊之处。它可以在系统启动时从启动脚本/etc/rc.d中启动,可以由inetd守护进程启动,可以有作业规划进程crond启动,还可以由用户终端(通常是shell)执行。

总之,除开这些特殊性以外,守护进程与普通进程基本上没有什么区别。因此,编写守护进程实际上是把一个普通进程按照上述的守护进程的特性改造成为守护进程。如果大家对进程的认识比较深入,就对守护进程容易理解和编程了。

首先我们来察看一些常用的系统守护进程,看一下他们和几个概念:进程组、控制终端和对话期有什么联系。p s命令打印系统中各个进程的状态。该命令有多个选择项,有关细节请参考系统手册。为了察看所需的信息,执行:
ps –axj

PPID PID PGID SID TTY TPGID STAT UID TIME COMMAND
0 1 0 0 ? -1 S 0 0:04 init
1 2 1 1 ? -1 SW 0 0:00 [keventd]
1 3 1 1 ? -1 SW 0 0:00 [kapm-idled]
0 4 1 1 ? -1 SWN 0 0:00 [ksoftirqd_CPU0]
0 5 1 1 ? -1 SW 0 0:00 [kswapd]
0 6 1 1 ? -1 SW 0 0:00 [kreclaimd]
0 7 1 1 ? -1 SW 0 0:00 [bdflush]
0 8 1 1 ? -1 SW 0 0:00 [kupdated]
1 9 1 1 ? -1 SW< 0 0:00 [mdrecoveryd]
1 17 1 1 ? -1 SW 0 0:02 [kjournald]
1 92 1 1 ? -1 SW 0 0:00 [khubd]
1 573 573 573 ? -1 S 0 0:03 syslogd -r -x
1 578 578 578 ? -1 S 0 0:00 klogd -2
1 598 598 598 ? -1 S 32 0:00 portmap

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

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

在接触实际编程前,我们来看看编写守护进程要碰到的概念:进程组合会话期。

进程组

每个进程除了有一进程ID之外,还属于一个进程组(在讨论信号时就会涉及进程组)进程组是一个或多个进程的集合。每个进程有一个唯一的进程组ID。进程组ID类似于进程ID——它是一个正整数,并可存放在pid_t数据类型中。

每个进程组有一个组长进程。组长进程的标识是,其进程组ID等于其进程ID,进程组组长可以创建一个进程组,创建该组中的进程,然后终止,只要在某个进程组中有一个进程存在,则该进程就存在,这与其组长进程是否终止无关。从进程组创建开始到其中最后一个进程离开为止的时间区间称为进程组的生命期。某个进程组中的最后一个进程可以终止,也可以参加另一进程组。

前面已经提到进程调用setgid可以参加一个现存的组或者创建一个新进程组(setsid也可以创建一个新的进程组,后面将用到)

会话期

会话期(session)是一个或多个进程组的集合。其中,在一个会话期中有3个进程组,通常是有shell的管道线将几个进程编成一组的。

下面说明有关会话期和进程组的一些特性:

一个会话期可以有一个单独的控制终端(controlling terminal),这一般是我们在其上登录的终端设备(终端登录)或伪终端设备(网络登录),但这个控制终端并不是必需的。

建立与控制终端连接的会话期首进程,被称之为控制进程(contronlling process)。以及一个会话期中的几个进程组可被分为一个前台进程组(foreground process group)以及一个或几个后台进程组(background process group)

如果一个会话期有一个控制终端,则它有一个前台进程组,其他进程组为后台进程组。无论何时键入中断键(常常是delete或ctrl-c)或退出键(通常是ctrl-/),就会造成将中断信号或退出信号送至前途进程组的所有进程。

守护进程的编程规则

在不同Unix环境下,守护进程的具体编程细节并不一致。但所幸的是,守护进程的编程原则其实都一样,区别仅在于具体的实现细节不同,这个原则就是要满足守护进程的特性。编程规则如下:

1、在后台运行

为避免挂起控制终端,要将daemon放入后台执行,其方法是,在进程中调用fork使父进程终止,让daemon在子进程中后台执行。具体就是调用f o r k ,然后使父进程e x i t 。这样做实现了下面几点:
第一,如果该精灵进程是由一条简单s h e l l 命令起动的,那么使父进程终止使得s h e l l 认为这条命令已经执行完成。
第二,子进程继承了父进程的进程组I D ,但具有一个新的进程I D ,这就保证了子进程不是一个进程组的首进程。这对于下面就要做的s e t s i d 调用是必要的前提条件。

2、脱离控制终端,登录会话和进程组

登录会话可以包含多个进程组,这些进程组共享一个控制终端,这个控制终端通常是创建进程的登录终端、控制终端,登录会话和进程组通常是从父进程继承下来的。我们的目的就是要摆脱它们,使之不受它们的影响。

其方法是在第一点的基础上,调用setsid()使进程成为会话组长:

需要说明的是,当进程是会话组长时,setsid()调用会失败,但第一点已经保证进程不是会话组长。setsid()调用成功后,进程成为新的会话组长和新的进程组长,并与原来的登录会话和进程组脱离,由于会话过程对控制终端的独占性,进程同时与控制终端脱离。
具体是操作就是:
(a )成为新对话期的首进程
(b )成为一个新进程组的首进程
(c )没有控制终端。

3、禁止进程重新打开控制终端

现在,进程已经成为无终端的会话组长,但它可以重新申请打开一个控制终端。可以通过使进程不再成为会话组长来禁止进程重新打开控制终端:

4、关闭打开的文件描述符

进程从创建它的父进程那里继承了打开的文件描述符。如不关闭,将会浪费系统资源,造成进程所在地文件系统无法卸下以及无法预料的错误。一般来说,必要的是关闭0、1、2三个文件描述符,即标准输入、标准输出、标准错误。因为我们一般希望守护进程自己有一套信息输出、输入的体系,而不是把所有的东西都发送到终端屏幕上。调用fclose();

5、改变当前工作目录

将当前工作目录更改为根目录。从父进程继承过来的当前工作目录可能在一个装配的文件系统中。因为精灵进程通常在系统再引导之前是一直存在的,所以如果精灵进程的当前工作目录在一个装配文件系统中,那么该文件系统就不能被拆卸。

另外,某些精灵进程可能会把当前工作目录更改到某个指定位置,在此位置做它们的工作。例如,行式打印机假脱机精灵进程常常将其工作目录更改到它们的s p o o l 目录上。
可以调用chdir(“目录”);

6、重设文件创建掩码

将文件方式创建屏蔽字设置为0 。由继承得来的文件方式创建屏蔽字可能会拒绝设置某些许可权。例如,若精灵进程要创建一个组可读、写的文件,而继承的文件方式创建屏蔽字,屏蔽了这两种许可权,则所要求的组可读、写就不能起作用。

7、处理SIGCHLD 信号

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

signal(SIGCHLD,SIG_IGN);

这样,内核在子进程结束时不会产生僵尸进程,这一点与BSD4不同,在BSD4下必须显示等 待子进程结束才能释放僵尸进程。

守护进程实例

守护进程实例包括两部分:主程序test.c和初始化程序init.c。主程序每隔一分钟向/tmp
目录中的日志test.log 报告运行状态。初始化程序中的init_daemon 函数负责生成守护进程

void make_daemon(void)
{
pid_t pid;
FILE * lockfd;
sigset_t sighup;
int i;

extern pid_t getsid(pid_t);
pid = fork();//第一个子进程生成
if (pid < 0) {
printinfo("fork error!",INFOERROR);
exit(FAILEXIT);
}else if (pid > 0) {
printinfo("fork 1 ok! ", INFOSCREEN);
exit(OKEXIT);//退出父进程,摆脱shell的控制
}
pid = getpid();//获得子进程自身的id
lockfd = fopen(PIDFILE, "w");//以下是将pid写入文件
if (lockfd != NULL) {
fprintf(lockfd, "%d/n", pid);
fclose(lockfd);
}//写入pid
if (getsid(0) != pid) {//创建新的会话期
if (setsid() < 0) {
printinfo("backupdaemon setsid error!",INFOERROR);
perror("setsid");
}
}
if(pid=fork()){//再次生成子进程,这时候是孙子进程
exit(0);//退出上一代进程
}else if(pid<0){
exit(1);
}
close(1);//关闭文件
close(2);
chdir(rundir);//改变运行的目录
umask(022);//改变文件权限
}

守护进程的错误输出

守护进程不属于任何终端,所以当需要输出某些信息时,它无法像一般程序那样将信息直接输出到标准输出和标准错误输出中。我们很大时候也不希望每个守护进程将它自己的出错消息写到一个单独的文件中。因为对于系统管理人员而言,要记住哪一个守护进程写到哪一个记录文件中,并定期的检查这些文件,他一定会为此感到头疼的。所以,我们需要有一个集中的守护进程出错记录机制。目前很多系统都引入了syslog记录进程来实现这一目的。

自伯克利开发了BSD syslog并广泛应用以来,BSD syslog 机制被大多数守护进程所使用。我们下面介绍BSD syslog 的用法。有三种方法产生记录消息:

1 内核例程可以调用log函数。任何一个用户进程通过打开和读/dev/klog设备就可以读取这些消息。因为我们无意编写内核中的例程,所以不再进一步说明此函数。

2 大多数用户进程(守护进程)调用syslog函数以产生记录消息。我们将在下面说明其调用序列。这使消息发送至Unix域数据报套接口/dev/log。

3 在此主机上,或通过TCP/IP网络连接到此主机的某一其他主机上的一个用户进程可将记录消息发向UDP端口514。

注意:syslog 函数并不产生这些UDP数据报——它们要求产生此记录消息的进程具有显式的网络编程。

通常,syslog守护进程读取三种格式的记录消息。此守护进程在启动时读一个配置文件。一般来说,其文件名为/etc/syslog.conf,该文件决定了不同种类的消息应送向何处。例如,紧急消息可被送向系统管理员(若已登录),并在控制台上显示,而警告消息则可记录到一个文件中。该机制提供了syslog函数,其调用格式如下

#include 
void openlog (char*ident,int option ,int facility);
void syslog(int priority,char*format,……)
void closelog();

调用openlog是可选择的。如果不调用openlog,则在第一次调用syslog时,自动调用openlog。调用closelog也是可选择的,它只是关闭被用于与syslog守护进程通信的描述符。调用openlog 使我们可以指定一个ident,以后, 此ident 将被加至每则记录消息中。ident 一般是程序的名称(例如 ,cron ,inetd 等)。option 有4种可能:

LOG_CONS 若日志消息不能通过Unix域数据报发送至syslog,则将该消息写至控制台。

LOG_NDELAY1 立即打开Unix域数据报套接口至syslog守护进程,而不要等到记录第一消息。通常,在记录第一条消息之前,该套接口不打开。

LOG_PERROR 除将日志消息发送给syslog 外,还将它至标准出错。此选项仅由4.3BSDReno及以后版本支持。

LOG_PID 每条消息都包含进程ID。此选项可供对每个请求都fork一个子进程的守护进程使用。

在openlog中设置facility参数的目的是让配置文件可以说明,来自不同设施的消息以不同的方式进行处理。如果不调用openlog,或者以facility 为0来调用它,那么在调用syslog 时,可将facility作为priority参数的一个部分进行说明。调用syslog产生一个记录消息。其priority参数是facility和level的组合,它们可选取的值分别列于下面。level值按优先级从高级到最低按序排列

python版本:

1. 调用fork()以便父进程可以退出,这样就将控制权归还给运行你程序的命令行或shell程序。需要这一步以便保证新进程不是一个进程组头领进程(process group leader)。下一步,‘setsid()’,会因为你是进程组头领进程而失败。

2. 调用‘setsid()’ 以便成为一个进程组和会话组的头领进程。由于一个控制终端与一个会话相关联,而且这个新会话还没有获得一个控制终端,我们的进程没有控制终端,这对于守护程序来说是一件好事。

3. 再次调用‘fork()’所以父进程(会话组头领进程)可以退出。这意味着我们,一个非会话组头领进程永远不能重新获得控制终端。

4. 调用‘chdir("/")’确认我们的进程不保持任何目录于使用状态。不做这个会导致系统管理员不能卸装(umount)一个文件系统,因为它是我们的当前工作目录。 [类似的,我们可以改变当前目录至对于守护程序运行重要的文件所在目录]

5. 调用‘umask(0)’以便我们拥有对于我们写的任何东西的完全控制。我们不知道我们继承了什么样的umask。 [这一步是可选的](译者注:这里指步骤5,因为守护程序不一定需要写文件)

6. 调用‘close()’关闭文件描述符0,1和2。这样我们释放了从父进程继承的标准输入,标准输出,和标准错误输出。我们没办法知道这些文描述符符可能已经被重定向去哪里。注意到许多守护程序使用‘sysconf()’来确认‘_SC_OPEN_MAX’的限制。‘_SC_OPEN_MAX’告诉你每个进程能够打开的最多文件数。然后使用一个循环,守护程序可以关闭所有可能的文件描述符。你必须决定你需要做这个或不做。如果你认为有可能有打开的文件描述符,你需要关闭它们,因为系统有一个同时打开文件数的限制。

7. 为标准输入,标准输出和标准错误输出建立新的文件描述符。即使你不打算使用它们,打开着它们不失为一个好主意。准确操作这些描述符是基于各自爱好;比如说,如果你有一个日志文件,你可能希望把它作为标准输出和标准错误输出打开,而把‘/dev/null’作为标准输入打开;作为替代方法,你可以将‘/dev/console’作为标准错误输出和/或标准输出打开,而‘/dev/null’作为标准输入,或者任何其它对你的守护程序有意义的结合方法。(译者注:一般使用dup2函数原子化关闭和复制文件描述符。

def createDaemon():    
        import os
        
        # create - fork 1
        try:
                if os.fork() > 0: 
                        os._exit(0)
        except OSError, error:
                print 'fork #1 failed: %d (%s)' % (error.errno, error.strerror)
            os._exit(1)
     
        # it separates the son from the father
        os.chdir('/')
        os.setsid()
        os.umask(0)
     
        # create - fork 2
        try:
                pid = os.fork()
            if pid > 0:
                print 'Daemon PID %d' % pid
                os._exit(0)
        except OSError, error:
            print 'fork #2 failed: %d (%s)' % (error.errno, error.strerror)
            os._exit(1)
     
        funzioneDemo() # function demo
        
def funzioneDemo():
     
        import time
     
        fd = open('/tmp/demone.log', 'w')
        while True:
                fd.write(time.ctime()+'\n')
            fd.flush()
            time.sleep(2)
        fd.close()
        
if __name__ == '__main__':
     
        createDaemon()

转自http://blog.csdn.net/dysj4099/article/details/18219411

由于需要为OpenStack中的虚拟机设计监控Agent,因此需要一个稳妥、可靠并简单的守护进程实现作为基础框架,故研究了一下Linux系统中的守护进程。

首先,守护进程是一类在后台执行,生命周期较长的进程,它一般随系统启动运行,在系统关闭的时候停止。翻译了一下《Advanced Programming in The Unix Environment  Section》的第13.3小节,此小节是一个关于守护进程的设计规范,罗列了守护进程设计实现的几大原则:

翻译《AdvancedProgrammingin The Unix Environment》Section 13.3 Page 583

守护进程编码规范:

本小节将介绍一些守护进程的基本编码规范,这些规范将阻止守护进程与当前环境产生一些不必要的交互。本节将通过一个函数daemonize实现这些规范。

1.     首先要做的被称为 umask,这一步骤会将文件创建掩码重置为0。这一步的原因是守护进程继承(inherited)得到的文件掩码有可能会拒绝某些特定的文件操作权限。如果守护进程想要创建文件,那有可能它需要设置特定的文件操作权限。例如,如果守护进程想要创建允许组读和写(group-readand group-write)权限的文件,但继承得到的文件创建掩码屏蔽了这个权限,则创建操作不会成功。

2.    调用 fork 并使父进程退出(exit)。这一步骤的目的在于。首先,如果守护进程是通过一个简单的shell命令建立的,那么在父进程终止的时候shell会认为命令已经结束了继而结束守护进程。其次,子进程继承得到父进程的groupID同时也获得了一个新的进程号,所以我们必须得保证子进程不能担任groupleader的角色,这是下一步setsid 操作的前提。

注:此步骤是使得进程在后台运行。

3.    调用 setsid 创建一个新的会话。有三个步骤将会执行:(a)进程将成为这个新会话的sessionleader角色,(b)此进程将会成为一个新的进程组的groupleader,(c)此进程将不会有控制终端。

注:此步骤将使得进程脱离控制终端、登录会话以及进程组。

·     在基于SystemV的系统中,有建议再一次调用fork 并使父进程退出。而新产生的进程将会成为真正的守护进程。这一步骤将保证守护进程不是一个sessionleader,进而阻止它获取一个控制终端。或者另一种阻止守护进程获取控制终端的方案是任意时刻打开一个终端设备的时候确保指定O_NOCTTY。

注:此步骤将禁止进程重新打开控制终端。

4.    将当前的工作目录切换到系统根目录下。因为从父进程集成来的当前工作目录可能是一个被挂载的文件系统。因为守护进程通常是直到系统重启的时候才会退出,如果守护进程的工作目录在一个挂载的文件系统上,那么这个文件系统就不能被卸载(unmounted)。

·      有的守护进程可能会将当前的工作目录切换到一些特定的路径,在这些路径下它们将完成它们的工作。例如,lineprinter spoolingdaemons 通常将工作目录切换为spool目录。

5.    一些不必要的文件描述符将会被关闭。这个步骤将阻止守护进程保持从父进程集成到的任何已经打开的文件描述符(也可能是shell或其他进程)。我们可以使用 open_max 函数或 getrlimit 函数来查找当前优先级最高的文件描述符并关闭此描述符之下的所有其他描述符。

注:保持打开的描述符将会占用系统资源并可能使某些文件不能被卸载。

6.    有一些守护进程将打开文件描述符0, 1, 2 指向 /dev/null ,这样一来所有试图从标准输入、输出及错误读取守护进程信息的操作都不能成功。因为守护进程当前已经不与任何终端设备相关联,没有地方显示其输出或接受用户的输入。即使守护进程是从一个交互式session创建的,守护进程也将运行在后台,任何终端的登录与终止将不会影响守护进程。如果有其他用户通过当前的终端登录,我们也不希望守护进程的输出出现在终端上,并且该用户的任何输入也不会被守护进程接收。

总结起来就是:

1) 第一次fork将会创建父-子进程,同时使得父进程退出保证守护进程能够运行在后台。

2) 通过setsid步骤使得进程与控制终端、登录会话以及进程组脱离。

3) 第二次fork将确保进程重新打开控制终端,并且产生子-孙进程,而子进程退出后孙进程将成为真正的守护进程。

4) 其他还有一些诸如工作目录设置、关闭文件描述符、设置文件创建掩码之类的操作。

最后看一个python实现的例子,代码来自:http://www.jejik.com/articles/2007/02/a_simple_unix_linux_daemon_in_python/

[python]  view plain copy
  1. #!/usr/bin/env python
  2. import sys, os, time, atexit
  3. from signal import SIGTERM
  4. class Daemon:
  5. """
  6. A generic daemon class.
  7. Usage: subclass the Daemon class and override the run() method
  8. """
  9. def __init__(self, pidfile, stdin='/dev/null', stdout='/dev/null', stderr='/dev/null'):
  10. self.stdin = stdin
  11. self.stdout = stdout
  12. self.stderr = stderr
  13. self.pidfile = pidfile
  14. def daemonize(self):
  15. """
  16. do the UNIX double-fork magic, see Stevens' "Advanced
  17. Programming in the UNIX Environment" for details (ISBN 0201563177)
  18. http://www.erlenstar.demon.co.uk/unix/faq_2.html#SEC16
  19. """
  20. try:
  21. pid = os.fork()
  22. if pid > 0:
  23. # exit first parent
  24. sys.exit(0)
  25. except OSError, e:
  26. sys.stderr.write("fork #1 failed: %d (%s)\n" % (e.errno, e.strerror))
  27. sys.exit(1)
  28. # decouple from parent environment
  29. os.chdir("/")
  30. os.setsid()
  31. os.umask(0)
  32. # do second fork
  33. try:
  34. pid = os.fork()
  35. if pid > 0:
  36. # exit from second parent
  37. sys.exit(0)
  38. except OSError, e:
  39. sys.stderr.write("fork #2 failed: %d (%s)\n" % (e.errno, e.strerror))
  40. sys.exit(1)
  41. # redirect standard file descriptors
  42. sys.stdout.flush()
  43. sys.stderr.flush()
  44. si = file(self.stdin, 'r')
  45. so = file(self.stdout, 'a+')
  46. se = file(self.stderr, 'a+', 0)
  47. os.dup2(si.fileno(), sys.stdin.fileno())
  48. os.dup2(so.fileno(), sys.stdout.fileno())
  49. os.dup2(se.fileno(), sys.stderr.fileno())
  50. # write pidfile
  51. atexit.register(self.delpid)
  52. pid = str(os.getpid())
  53. file(self.pidfile,'w+').write("%s\n" % pid)
  54. def delpid(self):
  55. os.remove(self.pidfile)
  56. def start(self):
  57. """
  58. Start the daemon
  59. """
  60. # Check for a pidfile to see if the daemon already runs
  61. try:
  62. pf = file(self.pidfile,'r')
  63. pid = int(pf.read().strip())
  64. pf.close()
  65. except IOError:
  66. pid = None
  67. if pid:
  68. message = "pidfile %s already exist. Daemon already running?\n"
  69. sys.stderr.write(message % self.pidfile)
  70. sys.exit(1)
  71. # Start the daemon
  72. self.daemonize()
  73. self.run()
  74. def stop(self):
  75. """
  76. Stop the daemon
  77. """
  78. # Get the pid from the pidfile
  79. try:
  80. pf = file(self.pidfile,'r')
  81. pid = int(pf.read().strip())
  82. pf.close()
  83. except IOError:
  84. pid = None
  85. if not pid:
  86. message = "pidfile %s does not exist. Daemon not running?\n"
  87. sys.stderr.write(message % self.pidfile)
  88. return # not an error in a restart
  89. # Try killing the daemon process
  90. try:
  91. while 1:
  92. os.kill(pid, SIGTERM)
  93. time.sleep(0.1)
  94. except OSError, err:
  95. err = str(err)
  96. if err.find("No such process") > 0:
  97. if os.path.exists(self.pidfile):
  98. os.remove(self.pidfile)
  99. else:
  100. print str(err)
  101. sys.exit(1)
  102. def restart(self):
  103. """
  104. Restart the daemon
  105. """
  106. self.stop()
  107. self.start()
  108. def run(self):
  109. """
  110. You should override this method when you subclass Daemon. It will be called after the process has been
  111. daemonized by start() or restart().
  112. """

Daemon.daemonize()方法就是执行了上述的步骤。如果需要使用此守护进程类,请继承Daemon类并自行实现run方法。

[python]  view plain copy
  1. #!/usr/bin/env python
  2. import sys, time
  3. from daemon import Daemon
  4. class MyDaemon(Daemon):
  5. def run(self):
  6. while True:
  7. time.sleep(1)
  8. if __name__ == "__main__":
  9. daemon = MyDaemon('/tmp/daemon-example.pid')
  10. if len(sys.argv) == 2:
  11. if 'start' == sys.argv[1]:
  12. daemon.start()
  13. elif 'stop' == sys.argv[1]:
  14. daemon.stop()
  15. elif 'restart' == sys.argv[1]:
  16. daemon.restart()
  17. else:
  18. print "Unknown command"
  19. sys.exit(2)
  20. sys.exit(0)
  21. else:
  22. print "usage: %s start|stop|restart" % sys.argv[0]
  23. sys.exit(2)

参考资料:

http://www.jejik.com/articles/2007/02/a_simple_unix_linux_daemon_in_python/

http://www.zhouxiongzhi.net/tech/double-fork-when-creating-daemon/

http://blog.163.com/yungang_z/blog/static/175153133201232462140622/

Linux守护进程设计规范及python实现相关推荐

  1. python实现守护进程_守护进程原理及Python实现

    守护进程原理及Python实现 守护进程,不依赖于终端,在后台运行的程序,通常称为daemon(ˈdiːmən或ˈdeɪmən). 一些常见的Linux软件通常都是已守护进程的方式运行,比如: ngi ...

  2. Linux守护进程实现

    Linux守护进程 redis版: void daemonize(void) {int fd;if (fork() != 0) exit(0); /* parent exits */setsid(); ...

  3. Linux 命令详解(六)Linux 守护进程的启动方法

    Linux 守护进程的启动方法 http://www.ruanyifeng.com/blog/2016/02/linux-daemon.html

  4. .NET跨平台实践:.NetCore、.Net5/6 Linux守护进程设计

    几年前,我写过两篇关于用C#开发Linux守护进程的技术文章,分别是<.NET跨平台实践:用C#开发Linux守护进程.NET跨平台实践:再谈用C#开发Linux守护进程 - 完整篇 这就是本文 ...

  5. .NET跨平台实践:再谈用C#开发Linux守护进程 — 完整篇

    Linux守护进程是Linux的后台服务进程,相当于Windows服务,对于为Linux开发服务程序的朋友来说,Linux守护进程相关技术是必不可少的,因为这个技术不仅仅是为了开发守护进程,还可以拓展 ...

  6. .NET跨平台实践:用C#开发Linux守护进程

    Linux守护进程(Daemon)是Linux的后台服务进程,它脱离了与控制终端的关联,直接由Linux init进程管理其生命周期,即使你关闭了控制台,daemon也能在后台正常工作. 一句话,为L ...

  7. 深入理解Linux守护进程

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

  8. Linux守护进程的创建(结合nginx框架)

    Linux守护进程的创建(结合nginx框架) 先介绍几个相关函数: int dup2(arg1,arg2):参数一指向的内容赋给参数二,shi的参数二也能访问参数一所指向的内容,并返回新的描述符 i ...

  9. linux+守护进程+php,【转载】Linux 守护进程的编程方法

    [转载]Linux 守护进程的编程方法 原文见: http://www.linuxdevelop.org/tingxx/show.php?table=c&id=3 Linux 守护进程的编程方 ...

最新文章

  1. html小球跳跃技术原理,弹跳的小球.html · web-project-songyu/原生js小例子 - Gitee.com...
  2. java slf4j日志框架_SLF4J - 日志框架 - 类库 - Java - 代码树
  3. Excel表中分类汇总数据如何只复制结果
  4. qt git linux 安装,git – 如何在Ubuntu上安装QtWebEngine
  5. Adblock Plus cjxlist 规则说明与反馈贴
  6. Thinkphp 发送邮件
  7. LINQ简记(1):基本语法
  8. 《Android开发精要》读书笔记——Android应用模型
  9. 看看webpack打包优化
  10. CentOS下MYSQL数据库的安装
  11. WCF服务启动时遇到AddressAccessDeniedException
  12. # 二极管的种类(1)-稳压二极管的参数与应用
  13. eclipse svn忽略指定文件或文件夹
  14. 01_开关电源设计-电源反馈电路怎么设计?TL431配合光耦反馈电路实例设计
  15. javaWeb实现短信验证码发送
  16. 数据可视化之智能bi实现生态绿地数据可视化分析
  17. su: 无法设置组: 不允许的操作
  18. java 连接多实例_Java如何连接多实例SQL Server?
  19. 常用MIME类型(Mp4的mime类型设置)
  20. 高炉炼铁车间人工巡视被淘汰是工业发展的必然

热门文章

  1. 怎么用matlab画一个笑脸,MATLAB笑脸识别
  2. 华为交换机SSH配置
  3. SQL的select 语句的执行顺序
  4. labelimg标注yolo格式Bug
  5. Matlab论文插图绘制模板第69期—带误差棒的折线图(Errorbar)
  6. java gef_GEF开发入门要点(个人经验)
  7. 使用certbot为nginx站点添加免费ssl证书
  8. 关于Java八种原始数据类型
  9. 《佛密诸事》第十一章:解读大悲咒
  10. 开源 android 播放器