Skip to content

Latest commit

 

History

History

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
 
 
 
 
 
 
 
 

README.md

使用

需要修改部分

  • pid 文件位置
  • 运行程序
class MyDaemon(Daemon):
    def run(self):
        ##########################################需要修改部分
        ceshi.ceshi()
        ##########################################

启动后如何查看进程

  • pid 文件是否存在
  • ps -ef | grep python
  • python ./run_daemon.py agent status

原理

linux 创建守护进程的步骤如下:

    1  创建子进程,父进程退出

    这是创建守护进程的第一步。由于守护进程是脱离控制终端的,因此,完成第一步后就会在 Shell
终端里造成一程序已经运行完毕的假象。之后的所有工作都在子进程中完成,而用户在 Shell 终端里则
可以执行其他命令,从而在形式上做到了与控制终端的脱离。在 Linux 中父进程先于子进程退出会造成
子进程成为孤儿进程,而每当系统发现一个孤儿进程是,就会自动由 1 号进程(init)收养它,这样,
原先的子进程就会变成 init 进程的子进程。

    2  在子进程中创建新会话

    Linux 是一个多用户多任务系统,每个进程都有一个进程 ID,同时每个进程还都属于某一个进程组,
而每个进程组都有一个组长进程,组长进程的标识 ID 等于进程组的 ID,且该进程组 ID 不会因组长进程的
退出而受到影响。会话期是一个或多个进程组的集合,通常,一个会话开始与用户登录,终止于用户退
出,在此期间该用户运行的所有进程都属于这个会话期。一个会话期可以有一个单独的控制终端,只有
其前台进程才可以拥有控制终端,实现与用户的交互。从 shell 中启动的每一个进程将继承一个与之相结
合的终端,以便进程与用户交互,但是守护进程不需要这些,子进程继承父进程的会话期和进程组 ID,
子进程会受到发送给该会话期的信号的影响,所以守护进程应该创建一个新的会话期,这个步骤是创建
守护进程中最重要的一步,虽然它的实现非常简单,但它的意义却非常重大。在这里使用的是系统函数
setsid 来实现的。

    setsid 函数用于创建一个新的会话,并担任该会话组的组长。调用 setsid 有下面的 3 个作用:
    让进程摆脱原会话的控制
    让进程摆脱原进程组的控制
    让进程摆脱原控制终端的控制

    由于创建守护进程的第一步调用了 fork 函数来创建子进程,再将父进程退出。在调用 fork 函数时,
子进程全盘拷贝了父进程的会话期、进程组、控制终端等,虽然父进程退出了,但会话期、进程组、控
制终端等并没有改变,因此,还还不是真正意义上的独立开来,而 setsid 函数能够使进程完全独立出来
,从而摆脱其他进程的控制。

    3  改变当前目录为根目录

    使用 fork 创建的子进程继承了父进程的当前工作目录。守护进程不应当使用父进程的工作目录,应
该设置自己的工作目录,通常可以通过 chdir() 来完成,一般可以将其设置为根目录,不过有些守护进程
需要将它设置到自己特定的工作目录,但此时必须保证所设置的工作目录处于一个不能卸载的文件系统
中,因为守护进程通常在系统引导后是一直存在的。

    4  重设文件权限掩码

    守护进程从父进程继承来的文件创建方式掩码可能会拒绝设置某些许可权限,文件权限掩码是指屏
蔽掉文件权限中的对应位。比如,有个文件权限掩码是 050,它就屏蔽了文件组拥有者的可读与可执行权
限。由于使用 fork 函数新建的子进程继承了父进程的文件权限掩码,可能使守护进程的执行出现问题,
因此,把文件权限掩码设置为 0,可以大大增强该守护进程的灵活性。设置文件权限掩码的函数是 umask。
在这里,通常的使用方法为 umask(0)。

    5  关闭文件描述符

    一般情况下,进程启动时都会自动打开终端文件,但是守护进程已经与终端脱离,所以终端描述符应
该关闭。用 fork 函数新建的子进程也会从父进程那里继承一些已经打开了的文件。这些被打开的文件可能
永远不会被守护进程读写,但它们一样消耗系统资源,而且可能导致所在的文件系统无法卸下。

    6  忽略 SIGCHLD 信号

    这一步只对需要创建子进程的守护进程才有必要,很多服务器守护进程设计成通过派生子进程来处理
客户端的请求,如果父进程不对 SIGCHLD 信号进行处理的话,子进程在终止后变成僵尸进程,通过将信号
SIGCHLD 的处理方式设置为 SIG_IGN 可以避免这种情况发生。

    7  用日志系统记录出错信息

    因为守护进程没有控制终端,当进程出现错误时无法写入到标准输出上,可以通过调用 syslog 将出
错信息写入到指定的文件中。

    8  守护进程退出处理

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

关于两次 fork

第二个 fork 不是必须的,只是为了防止进程打开控制终端。

打开一个控制终端的条件是该进程必须是 session leader。第一次 fork,setsid 之后,子进程成为 session leader,进程可以打开终端;第二次 fork 产生的进程,不再是 session leader,进程则无法打开终端。

也就是说,只要程序实现得好,控制程序不主动打开终端,无第二次 fork 亦可。