精华内容
下载资源
问答
  • 创建守护进程

    2015-09-25 23:41:17
    创建守护进程的步骤: 1、让init进程成为新产生进程的父进程  具体方法:调用fork()函数创建子进程后,使父进程立即退出。 2、调用setsid函数 调用setsid函数,使得新创建的进程脱离控制终端,同时创建新的进程...

    守护进程,也称为精灵进程,是一种运行在后台的特殊进程,它不存在控制终端,

    并周期性地执行某项任务或者等待处理某项任务。

    创建守护进程的步骤:

    1、让init进程成为新产生进程的父进程

      具体方法:调用fork()函数创建子进程后,使父进程立即退出。

    2、调用setsid函数

    调用setsid函数,使得新创建的进程脱离控制终端,同时创建新的进程组,并成为

    该进程组的首进程。

    3、更改当前工作目录

    由于子进程继承了父进程的当前工作目录,所以需要将子进程即要创建的守护进程

    的工作目录更改为守护进程需要的工作目录,一般将守护进程的工作目录设定为根目录

    (/目录),更改目录用chdir函数。

    4、关闭文件描述符,并重定向标准输入、输出和错误输出

    守护进程运行在后台,不能往终端输出任何信息,需要用dup函数将守护进程的标准

    输入、输出和错误输出重定向到/dev/null设备。

    5、设置守护进程创建的文件的权限

    守护进程在运行过程中可能会创建一些临时文件,而这些临时文件出于安全性方面的

    考虑,一般不能被其他用户浏览,这时就需要更改文件的权限,每次更改文件权限比较麻烦

    可以设置文件掩码,用umask设置好文件掩码之后就可以使得创建的文件的权限为设置的权限。


    具体实例如exampl.c:

    #include<stdlib.h>
    #include<unistd.h>
    #include<sys/types.h>
    #include<sys/stat.h>
    #include<fcntl.h>
    
    int daemon(int nochdir,int noclose)
    {
    	pid_t pid;
    	pid = fork();
    	if(pid < 0)
    	{
    	perror("fork");
    	return -1;
    	}
    		
    	if(pid != 0)
    		exit(0);
    
    	pid = setsid();
    
    	if(pid < -1)
    	{
    	perror("setpid");
    	return -1;
    	}
    
    	if(!nochdir)
    		chdir("/");
    
    	if(!noclose)
    	{
    	int fd;
    	fd = open("/dev/full",O_RDWR, 0);
    	if(fd != -1)
    	{
    	dup2(fd, STDIN_FILENO);
    	dup2(fd, STDOUT_FILENO);
    	dup2(fd, STDOUT_FILENO);
    	if(fd > 2)
    		close(fd);
    	}
    	}
    
    	umask(0027);
    	return 0;
    	}
    
    int main(void)
    {
    	daemon(0,0);
    	sleep(1000);
    
    	return 0;
    }


    编译程序:gcc -o example example.c

    执行程序 ./example

    查询程序执行结果: ps -axj | grep example

    结果:

    2440  4207  4207  4207 ?           -1 Ss    1000   0:00 ./example
     3421  4209  4208  3421 pts/0     4208 S+    1000   0:00 grep --color=auto example

    第一行为./example进程信息, “ ? ” 表示该进程没有控制终端,TTY为?,即该进程

    为守护进程。




    展开全文
  • 自己创建守护进程

    2016-07-20 13:06:29
    创建守护进程有两种方式,一种是通过系统提供的函数实现,另一种是模仿函数的底层实现。 (一)自己创建 1.调用umask将文件模式创建屏蔽字设置为0 2.调用fork,并且父进程退出 3.调用setsid创建一个新的会话 4....

            创建守护进程有两种方式,一种是通过系统提供的函数实现,另一种是模仿函数的底层实现。

    (一)自己创建

    1.调用umask将文件模式创建屏蔽字设置为0

    2.调用fork,并且父进程退出

    3.调用setsid创建一个新的会话

    4.将当前工作目录改成根目录。

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

    6.其他:忽略SIGCHLD信号

    以下是自己写的守护进程:

    运行结果如下:




    二)调用函数的方法

    #include <stdio.h>
    #include<unistd.h>
    int main()
    {
    daemon(0,0);
    while(1);
    }

    三)关于有时候创建守护进程需要两次fork的原因

    1 、第一次fork的作用是让shell 认为本条命令 已经终止,不用挂在终端输入上。还有一个作用是为后面setsid服务。setsid的调用者不能是进程组组长(group leader). 此时父进程是进程组组长。

    2、第2次fork不是必须的。也看到很多开源服务没有fork第二次。fork第二次主要目的是。防止进程再次打开一个控制终端。因为打开一个控制终端的前台条件是该进程必须是会话组长。再fork一次,子进程ID != sid(sid是进程父进程的sid)。所以也无法打开新的控制终端。

    展开全文
  • Python中创建守护进程

    千次阅读 2017-03-30 15:43:02
    转自:Python中创建守护进程 python 创建守护进程 python 的os.setdid()提供了类似linux c api的 setsid也可以通过unix双fork创建守护进程。 几个相关的函数 os.umask(0) #重设文件创建掩码,子进程会...

    转自:Python中创建守护进程

    python 创建守护进程

    • python 的os.setdid()提供了类似linux c api的 setsid
    • 也可以通过unix双fork创建守护进程。

      几个相关的函数

    1. os.umask(0) #重设文件创建掩码,子进程会从父进程继承所有权限,可以通过调用这个方法将文件创建掩码初始化成系统默认。
    2. os.setsid() #调用系统的setsid(),创建一个新的会话并创建组id
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    #!/usr/bin/env python
    #coding:utf8
    import sys, os
    def main():
        """ A demo daemon main routine, write a datestamp to
            /tmp/daemon-log every 10 seconds.
        """
        import time
        = open("/tmp/daemon-log""w")
        while 1:
            f.write('%s/n' % time.ctime(time.time()))
            f.flush()
            time.sleep(10)
    if __name__ == "__main__":
        # do the UNIX double-fork magic, see Stevens' "Advanced
        # Programming in the UNIX Environment" for details (ISBN 0201563177)
        try:
            pid = os.fork()
            if pid > 0:
                # exit first parent
                sys.exit(0)
        except OSError, e:
            print >>sys.stderr, "fork #1 failed: %d (%s)" % (e.errno, e.strerror)
            sys.exit(1)
        # decouple from parent environment
        os.chdir("/")
        os.setsid()
        os.umask(0)
        # do second fork
        try:
            pid = os.fork()
            if pid > 0:
                # exit from second parent, print eventual PID before
                print "Daemon PID %d" % pid
                sys.exit(0)
        except OSError, e:
            print >>sys.stderr, "fork #2 failed: %d (%s)" % (e.errno, e.strerror)
            sys.exit(1)
        # start the daemon main loop
        main()

      

    代码引用自从:http://code.activestate.com/recipes/66012/download/1/
    1. main为写时间戳的永久循环
    2. 运行后程序fork一个进程,如果fork成功则程序自己退出
    3. 通过setsid() 创建了一个独立于当前会话的进程
    4. 再一次fork一个进程,如果fork成功则当前程序退出
    5. 这时候进程的父进程就变成了 init,成为了一个独立的deamon


    转自:Python实例浅谈之五Python守护进程和脚本单例运行

    一、简介

         守护进程最重要的特性是后台运行;它必须与其运行前的环境隔离开来,这些环境包括未关闭的文件描述符、控制终端、会话和进程组、工作目录以及文件创建掩码等;它可以在系统启动时从启动脚本/etc/rc.d中启动,可以由inetd守护进程启动,也可以有作业规划进程crond启动,还可以由用户终端(通常是shell)执行。
           Python有时需要保证只运行一个脚本实例,以避免数据的冲突。 

    二、Python守护进程

    1、函数实现

    [html] view plain copy
     在CODE上查看代码片派生到我的代码片
    1. #!/usr/bin/env python  
    2. #coding: utf-8  
    3. import sys, os  
    4.   
    5. '''将当前进程fork为一个守护进程  
    6.    注意:如果你的守护进程是由inetd启动的,不要这样做!inetd完成了  
    7.    所有需要做的事情,包括重定向标准文件描述符,需要做的事情只有chdir()和umask()了  
    8. '''  
    9.   
    10. def daemonize (stdin='/dev/null'stdout='/dev/null'stderr='/dev/null'):  
    11.      #重定向标准文件描述符(默认情况下定向到/dev/null)  
    12.     try:   
    13.         pid = os.fork()   
    14.           #父进程(会话组头领进程)退出,这意味着一个非会话组头领进程永远不能重新获得控制终端。  
    15.         if pid > 0:  
    16.             sys.exit(0)   #父进程退出  
    17.     except OSError, e:   
    18.         sys.stderr.write ("fork #1 failed: (%d) %s\n" % (e.errno, e.strerror) )  
    19.         sys.exit(1)  
    20.   
    21.      #从母体环境脱离  
    22.     os.chdir("/")  #chdir确认进程不保持任何目录于使用状态,否则不能umount一个文件系统。也可以改变到对于守护程序运行重要的文件所在目录  
    23.     os.umask(0)    #调用umask(0)以便拥有对于写的任何东西的完全控制,因为有时不知道继承了什么样的umask。  
    24.     os.setsid()    #setsid调用成功后,进程成为新的会话组长和新的进程组长,并与原来的登录会话和进程组脱离。  
    25.   
    26.      #执行第二次fork  
    27.     try:   
    28.         pid = os.fork()   
    29.         if pid > 0:  
    30.             sys.exit(0)   #第二个父进程退出  
    31.     except OSError, e:   
    32.         sys.stderr.write ("fork #2 failed: (%d) %s\n" % (e.errno, e.strerror) )  
    33.         sys.exit(1)  
    34.   
    35.      #进程已经是守护进程了,重定向标准文件描述符  
    36.   
    37.     for f in sys.stdout, sys.stderr: f.flush()  
    38.     si = open(stdin, 'r')  
    39.     so = open(stdout, 'a+')  
    40.     se = open(stderr, 'a+', 0)  
    41.     os.dup2(si.fileno(), sys.stdin.fileno())    #dup2函数原子化关闭和复制文件描述符  
    42.     os.dup2(so.fileno(), sys.stdout.fileno())  
    43.     os.dup2(se.fileno(), sys.stderr.fileno())  
    44.   
    45. #示例函数:每秒打印一个数字和时间戳  
    46. def main():  
    47.     import time  
    48.     sys.stdout.write('Daemon started with pid %d\n' % os.getpid())  
    49.     sys.stdout.write('Daemon stdout output\n')  
    50.     sys.stderr.write('Daemon stderr output\n')  
    51.     c = 0  
    52.     while True:  
    53.         sys.stdout.write('%d: %s\n' %(c, time.ctime()))  
    54.         sys.stdout.flush()  
    55.         c = c+1  
    56.         time.sleep(1)  
    57.   
    58. if __name__ == "__main__":  
    59.       daemonize('/dev/null','/tmp/daemon_stdout.log','/tmp/daemon_error.log')  
    60.       main()  
            可以通过命令ps -ef | grep daemon.py查看后台运行的继承,在/tmp/daemon_error.log会记录错误运行日志,在/tmp/daemon_stdout.log会记录标准输出日志。

    2、类实现

    [html] view plain copy
     在CODE上查看代码片派生到我的代码片
    1. #!/usr/bin/env python  
    2. #coding: utf-8  
    3.   
    4. #python模拟linux的守护进程  
    5.   
    6. import sys, os, time, atexit, string  
    7. from signal import SIGTERM  
    8.   
    9. class Daemon:  
    10.   def __init__(self, pidfile, stdin='/dev/null'stdout='/dev/null'stderr='/dev/null'):  
    11.       #需要获取调试信息,改为stdin='/dev/stdin'stdout='/dev/stdout'stderr='/dev/stderr',以root身份运行。  
    12.     self.stdin = stdin  
    13.     self.stdout = stdout  
    14.     self.stderr = stderr  
    15.     self.pidfile = pidfile  
    16.     
    17.   def _daemonize(self):  
    18.     try:  
    19.       pid = os.fork()    #第一次fork,生成子进程,脱离父进程  
    20.       if pid > 0:  
    21.         sys.exit(0)      #退出主进程  
    22.     except OSError, e:  
    23.       sys.stderr.write('fork #1 failed: %d (%s)\n' % (e.errno, e.strerror))  
    24.       sys.exit(1)  
    25.     
    26.     os.chdir("/")      #修改工作目录  
    27.     os.setsid()        #设置新的会话连接  
    28.     os.umask(0)        #重新设置文件创建权限  
    29.     
    30.     try:  
    31.       pid = os.fork() #第二次fork,禁止进程打开终端  
    32.       if pid > 0:  
    33.         sys.exit(0)  
    34.     except OSError, e:  
    35.       sys.stderr.write('fork #2 failed: %d (%s)\n' % (e.errno, e.strerror))  
    36.       sys.exit(1)  
    37.     
    38.      #重定向文件描述符  
    39.     sys.stdout.flush()  
    40.     sys.stderr.flush()  
    41.     si = file(self.stdin, 'r')  
    42.     so = file(self.stdout, 'a+')  
    43.     se = file(self.stderr, 'a+', 0)  
    44.     os.dup2(si.fileno(), sys.stdin.fileno())  
    45.     os.dup2(so.fileno(), sys.stdout.fileno())  
    46.     os.dup2(se.fileno(), sys.stderr.fileno())  
    47.     
    48.      #注册退出函数,根据文件pid判断是否存在进程  
    49.     atexit.register(self.delpid)  
    50.     pid = str(os.getpid())  
    51.     file(self.pidfile,'w+').write('%s\n' % pid)  
    52.     
    53.   def delpid(self):  
    54.     os.remove(self.pidfile)  
    55.   
    56.   def start(self):  
    57.      #检查pid文件是否存在以探测是否存在进程  
    58.     try:  
    59.       pf = file(self.pidfile,'r')  
    60.       pid = int(pf.read().strip())  
    61.       pf.close()  
    62.     except IOError:  
    63.       pid = None  
    64.     
    65.     if pid:  
    66.       message = 'pidfile %s already exist. Daemon already running!\n'  
    67.       sys.stderr.write(message % self.pidfile)  
    68.       sys.exit(1)  
    69.       
    70.     #启动监控  
    71.     self._daemonize()  
    72.     self._run()  
    73.   
    74.   def stop(self):  
    75.     #从pid文件中获取pid  
    76.     try:  
    77.       pf = file(self.pidfile,'r')  
    78.       pid = int(pf.read().strip())  
    79.       pf.close()  
    80.     except IOError:  
    81.       pid = None  
    82.     
    83.     if not pid:   #重启不报错  
    84.       message = 'pidfile %s does not exist. Daemon not running!\n'  
    85.       sys.stderr.write(message % self.pidfile)  
    86.       return  
    87.   
    88.      #杀进程  
    89.     try:  
    90.       while 1:  
    91.         os.kill(pid, SIGTERM)  
    92.         time.sleep(0.1)  
    93.         #os.system('hadoop-daemon.sh stop datanode')  
    94.         #os.system('hadoop-daemon.sh stop tasktracker')  
    95.         #os.remove(self.pidfile)  
    96.     except OSError, err:  
    97.       err = str(err)  
    98.       if err.find('No such process') > 0:  
    99.         if os.path.exists(self.pidfile):  
    100.           os.remove(self.pidfile)  
    101.       else:  
    102.         print str(err)  
    103.         sys.exit(1)  
    104.   
    105.   def restart(self):  
    106.     self.stop()  
    107.     self.start()  
    108.   
    109.   def _run(self):  
    110.     """ run your fun"""  
    111.     while True:  
    112.       #fp=open('/tmp/result','a+')  
    113.       #fp.write('Hello World\n')  
    114.       sys.stdout.write('%s:hello world\n' % (time.ctime(),))  
    115.       sys.stdout.flush()   
    116.       time.sleep(2)  
    117.       
    118.   
    119. if __name__ == '__main__':  
    120.     daemon = Daemon('/tmp/watch_process.pid', stdout = '/tmp/watch_stdout.log')  
    121.     if len(sys.argv) == 2:  
    122.         if 'start' == sys.argv[1]:  
    123.             daemon.start()  
    124.         elif 'stop' == sys.argv[1]:  
    125.             daemon.stop()  
    126.         elif 'restart' == sys.argv[1]:  
    127.             daemon.restart()  
    128.         else:  
    129.             print 'unknown command'  
    130.             sys.exit(2)  
    131.         sys.exit(0)  
    132.     else:  
    133.         print 'usage: %s start|stop|restart' % sys.argv[0]  
    134.         sys.exit(2)  
    运行结果:

           可以参考http://www.jejik.com/articles/2007/02/a_simple_unix_linux_daemon_in_python/,它是当Daemon设计成一个模板,在其他文件中from daemon import Daemon,然后定义子类,重写run()方法实现自己的功能。

    [html] view plain copy
     在CODE上查看代码片派生到我的代码片
    1. class MyDaemon(Daemon):  
    2.     def run(self):  
    3.         while True:  
    4.             fp=open('/tmp/run.log','a+')  
    5.             fp.write('Hello World\n')  
    6.             time.sleep(1)  
            不足:信号处理signal.signal(signal.SIGTERM, cleanup_handler)暂时没有安装,注册程序退出时的回调函数delpid()没有被调用。
           然后,再写个shell命令,加入开机启动服务,每隔2秒检测守护进程是否启动,若没有启动则启动,自动监控恢复程序。      
    [html] view plain copy
     在CODE上查看代码片派生到我的代码片
    1. #/bin/sh  
    2. while true  
    3. do  
    4.   count=`ps -ef | grep "daemonclass.py" | grep -v "grep"`  
    5.   if [ "$?" != "0" ]; then  
    6.      daemonclass.py start  
    7.   fi  
    8.   sleep 2  
    9. done  

    三、python保证只能运行一个脚本实例

    1、打开文件本身加锁

    [html] view plain copy
     在CODE上查看代码片派生到我的代码片
    1. #!/usr/bin/env python  
    2. #coding: utf-8  
    3. import fcntl, sys, time, os  
    4. pidfile = 0  
    5.   
    6. def ApplicationInstance():  
    7.     global pidfile  
    8.     pidfile = open(os.path.realpath(__file__), "r")  
    9.     try:  
    10.         fcntl.flock(pidfile, fcntl.LOCK_EX | fcntl.LOCK_NB) #创建一个排他锁,并且所被锁住其他进程不会阻塞  
    11.     except:  
    12.         print "another instance is running..."  
    13.         sys.exit(1)  
    14.   
    15. if __name__ == "__main__":  
    16.     ApplicationInstance()  
    17.     while True:  
    18.         print 'running...'  
    19.         time.sleep(1)  
           注意:open()参数不能使用w,否则会覆盖本身文件;pidfile必须声明为全局变量,否则局部变量生命周期结束,文件描述符会因引用计数为0被系统回收(若整个函数写在主函数中,则不需要定义成global)。               

    2、打开自定义文件并加锁

    [html] view plain copy
     在CODE上查看代码片派生到我的代码片
    1. #!/usr/bin/env python  
    2. #coding: utf-8  
    3. import fcntl, sys, time  
    4. pidfile = 0  
    5.   
    6. def ApplicationInstance():  
    7.     global pidfile  
    8.     pidfile = open("instance.pid", "w")  
    9.     try:  
    10.         fcntl.lockf(pidfile, fcntl.LOCK_EX | fcntl.LOCK_NB)  #创建一个排他锁,并且所被锁住其他进程不会阻塞  
    11.     except  IOError:  
    12.         print "another instance is running..."  
    13.         sys.exit(0)  
    14.   
    15. if __name__ == "__main__":  
    16.     ApplicationInstance()  
    17.     while True:  
    18.         print 'running...'  
    19.         time.sleep(1)  

    3、检测文件中PID

    [html] view plain copy
     在CODE上查看代码片派生到我的代码片
    1. #!/usr/bin/env python  
    2. #coding: utf-8  
    3. import time, os, sys  
    4. import signal  
    5.   
    6. pidfile = '/tmp/process.pid'  
    7.   
    8. def sig_handler(sig, frame):  
    9.     if os.path.exists(pidfile):  
    10.         os.remove(pidfile)  
    11.     sys.exit(0)  
    12.   
    13. def ApplicationInstance():  
    14.     signal.signal(signal.SIGTERM, sig_handler)  
    15.     signal.signal(signal.SIGINT, sig_handler)  
    16.     signal.signal(signal.SIGQUIT, sig_handler)  
    17.   
    18.     try:  
    19.       pf = file(pidfile, 'r')  
    20.       pid = int(pf.read().strip())  
    21.       pf.close()  
    22.     except IOError:  
    23.       pid = None  
    24.     
    25.     if pid:  
    26.       sys.stdout.write('instance is running...\n')  
    27.       sys.exit(0)  
    28.   
    29.     file(pidfile, 'w+').write('%s\n' % os.getpid())  
    30.   
    31. if __name__ == "__main__":  
    32.     ApplicationInstance()  
    33.     while True:  
    34.         print 'running...'  
    35.         time.sleep(1)  
      

    4、检测特定文件夹或文件

    [html] view plain copy
     在CODE上查看代码片派生到我的代码片
    1. #!/usr/bin/env python  
    2. #coding: utf-8  
    3. import time, commands, signal, sys  
    4.   
    5. def sig_handler(sig, frame):  
    6.     if os.path.exists("/tmp/test"):  
    7.         os.rmdir("/tmp/test")  
    8.     sys.exit(0)  
    9.   
    10. def ApplicationInstance():  
    11.     signal.signal(signal.SIGTERM, sig_handler)  
    12.     signal.signal(signal.SIGINT, sig_handler)  
    13.     signal.signal(signal.SIGQUIT, sig_handler)  
    14.     if commands.getstatusoutput("mkdir /tmp/test")[0]:  
    15.         print "instance is running..."  
    16.         sys.exit(0)  
    17.   
    18. if __name__ == "__main__":  
    19.     ApplicationInstance()  
    20.     while True:  
    21.         print 'running...'  
    22.         time.sleep(1)  

           也可以检测某一个特定的文件,判断文件是否存在:

    [html] view plain copy
     在CODE上查看代码片派生到我的代码片
    1. import os  
    2. import os.path  
    3. import time  
    4.    
    5.    
    6. #class used to handle one application instance mechanism  
    7. class ApplicationInstance:  
    8.    
    9.     #specify the file used to save the application instance pid  
    10.     def __init__( self, pid_file ):  
    11.         self.pid_file = pid_file  
    12.         self.check()  
    13.         self.startApplication()  
    14.    
    15.     #check if the current application is already running  
    16.     def check( self ):  
    17.         #check if the pidfile exists  
    18.         if not os.path.isfile( self.pid_file ):  
    19.             return  
    20.         #read the pid from the file  
    21.         pid = 0  
    22.         try:  
    23.             file = open( self.pid_file, 'rt' )  
    24.             data = file.read()  
    25.             file.close()  
    26.             pid = int( data )  
    27.         except:  
    28.             pass  
    29.         #check if the process with specified by pid exists  
    30.         if 0 == pid:  
    31.             return  
    32.    
    33.         try:  
    34.             os.kill( pid, 0 )   #this will raise an exception if the pid is not valid  
    35.         except:  
    36.             return  
    37.    
    38.         #exit the application  
    39.         print "The application is already running..."  
    40.         exit(0) #exit raise an exception so don't put it in a try/except block  
    41.    
    42.     #called when the single instance starts to save it's pid  
    43.     def startApplication( self ):  
    44.         file = open( self.pid_file, 'wt' )  
    45.         file.write( str( os.getpid() ) )  
    46.         file.close()  
    47.    
    48.     #called when the single instance exit ( remove pid file )  
    49.     def exitApplication( self ):  
    50.         try:  
    51.             os.remove( self.pid_file )  
    52.         except:  
    53.             pass  
    54.    
    55.    
    56. if __name__ == '__main__':  
    57.     #create application instance  
    58.     appInstance = ApplicationInstance( '/tmp/myapp.pid' )  
    59.    
    60.     #do something here  
    61.     print "Start MyApp"  
    62.     time.sleep(5)   #sleep 5 seconds  
    63.     print "End MyApp"  
    64.    
    65.     #remove pid file  
    66.     appInstance.exitApplication()  
            上述os.kill( pid, 0 )用于检测一个为pid的进程是否还活着,若该pid的进程已经停止则抛出异常,若正在运行则不发送kill信号。

    5、socket监听一个特定端口

    [html] view plain copy
     在CODE上查看代码片派生到我的代码片
    1. #!/usr/bin/env python  
    2. #coding: utf-8  
    3. import socket, time, sys  
    4.   
    5.   
    6. def ApplicationInstance():  
    7.     try:      
    8.         global s  
    9.         s = socket.socket()  
    10.         host = socket.gethostname()  
    11.         s.bind((host, 60123))  
    12.     except:  
    13.         print "instance is running..."  
    14.         sys.exit(0)  
    15.   
    16. if __name__ == "__main__":  
    17.     ApplicationInstance()  
    18.     while True:  
    19.         print 'running...'  
    20.         time.sleep(1)  
    可以将该函数使用装饰器实现,便于重用(效果与上述相同):
    [html] view plain copy
     在CODE上查看代码片派生到我的代码片
    1. #!/usr/bin/env python  
    2. #coding: utf-8  
    3. import socket, time, sys  
    4. import functools  
    5.   
    6. #使用装饰器实现  
    7. def ApplicationInstance(func):  
    8.     @functools.wraps(func)  
    9.     def fun(*args,**kwargs):  
    10.         import socket  
    11.         try:  
    12.             global s  
    13.             s = socket.socket()  
    14.             host = socket.gethostname()  
    15.             s.bind((host, 60123))  
    16.         except:  
    17.             print('already has an instance...')  
    18.             return None  
    19.         return func(*args,**kwargs)  
    20.     return fun  
    21.   
    22. @ApplicationInstance  
    23. def main():  
    24.     while True:  
    25.         print 'running...'  
    26.         time.sleep(1)  
    27.   
    28. if __name__ == "__main__":  
    29.     main()  

    四、总结

    (1)守护进程和单脚本运行在实际应用中比较重要,方法也比较多,可选择合适的来进行修改,可以将它们做成一个单独的类或模板,然后子类化实现自定义。
    (2)daemon监控进程自动恢复避免了nohup和&的使用,并配合shell脚本可以省去很多不定时启动挂掉服务器的麻烦。
    (3)若有更好的设计和想法,可随时留言,在此先感谢!



    展开全文
  • 创建守护进程为什么要fork两次

    千次阅读 2017-06-19 17:12:27
    1、守护进程的概念与特点 2、创建守护进程 3、创建守护进程为什么需要fork两次

    一、守护进程的基本概念:
    守护进程也叫精灵进程,它是大多数服务器的载体。守护进程是一种运行在后台的一种特殊的进程,它独立于控制终端并且周期性的执行某种任务或是等待处理某些发生的时间。如果想让某个进程不因为用户或中断或其他变化而影响,那么就必须把这个进程变成一个守护进程。


    举个例子:在现实生活中, 许多大型的软件或服务器必须保证7*24小时(一周7天,一天24小时)无障碍的运行,例如淘宝网、百度搜索引擎、支付宝等等,那么像这样一种要一直运行的程序怎么实现呢?究其本质其实就是我们的守护进程。


    二、守护进程的特点:
    1).自成进程组,自成会话,与控制终端脱关联;
    2).守护进程的父进程是1号进程;
    3).守护进程的命令一般以字符d结尾;
    4).守护进程的生命周期是7*24小时不掉线;
    5).一般的网络服务器都以守护进程的形式在后台运行,比如常见的http,ftp等等服务器都是以守护进程的形式在后台运行;



    三、创建守护进程

    1、查看系统中的进程

    ps axj
    • 1

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



    2、setsid函数 
    (1)创建守护进程最关键的一步是调用setsid函数创建一个新的Session,并成为Session Leader。

    #include<unistd.h>
    pid_t setsid(void);
    • 1
    • 2

    返回值:该函数调用成功时返回新创建的Session的id(其实也就是当前进程的id),出错返回-1。


    (2)需要注意的是,,调用这个函数之前,当前进程不允许是进程组的Leader,否则该函数返回-1。 
    解决办法:先fork再调用setsid,fork创建的子进程和父进程在同一个进 程组中,进程组的Leader必然是该组的第一个进程,所以子进程不可能是该组的第一个进程,在子 进程中调用setsid就不会有问题了。


    (3)成功调用该函数的结果是: 
    1. 创建一个新的Session,当前进程成为Session Leader,当前进程的id就是Session的id。 
    2. 创建一个新的进程组,当前进程成为进程组的Leader,当前进程的id就是进程组的id。 
    3. 如果当前进程原本有一个控制终端,则它失去这个控制终端,成为一个没有控制终端的进程。所谓失去控制终端是指,原来的控制终端仍然是打开的,仍然可以读写,但只是一个普通的打开文件而不是控制终端了。


    3、创建守护进程的步骤 

    方式一:

    (1)调用umask将文件模式创建屏蔽字设置为0.

    umask(0);//umask必须清0,否则创建文件受系统默认权限的影响
    • 1

    文件权限掩码是屏蔽掉文件权限中的对应位。由于使用fork()函数新创建的子进程继承了父进程的文件权限掩码,这就给该子进程使用文件带了很多的麻烦(比如父进程中的文件没有执行文件的权限,然而在子进程中希望执行相应的文件这个时候就会出问题)。因此在子进程中要把文件的权限掩码设置成为0,即在此时有最大的权限,这样可以大大增强该守护进程的灵活性。


    (2)调用fork,父进程退出(exit)。 
    原因: 
    1)如果该守护进程是作为一条简单的shell命令启动的,那么⽗父进程终止使得shell认为该命令已经执行完毕。
    2)保证子进程不是一个进程组的组长进程。


    (3)调用setsid创建一个新会话。 
    setsid会导致: 
    1)调用进程成为新会话的首进程。 
    2)调用进程成为一个进程组的组长进程 。 
    3)调用进程没有控制终端。(再次fork一次,保证daemon进程,之后不会打开tty设备)

    调用setsid的原因: 
    由于创建守护进程的第一步是调用fork()函数来创建子进程,再将父进程退出。由于在调用了fork()函数的时候,子进程拷贝了父进程的会话期、进程组、控制终端等资源、虽然父进程退出了,但是会话期、进程组、控制终端等并没有改变,因此,需要用setsid()韩式来时该子进程完全独立出来,从而摆脱其他进程的控制。


    (4)将当前工作目录更改为根目录。 
    防止当前目录有一个目录被删除,导致守护进程无效。 
    使用fork()创建的子进程是继承了父进程的当前工作目录,由于在进程运行中,当前目录所在的文件系统是不能卸载的,这对以后使用会造成很多的麻烦。因此通常的做法是让“/”作为守护进程的当前目录,当然也可以指定其他的别的目录来作为守护进程的工作目录。


    (5)关闭不再需要的文件描述符。 
    同文件权限码一样,用fork()函数新建的子进程会从父进程那里继承一些已经打开了的文件。这些文件被打开的文件可能永远不会被守护进程读写,如果不进行关闭的话将会浪费系统的资源,造成进程所在的文件系统无法卸下以及引起预料的错误。

    如:关闭标准输入流、标准输出流、标准错误流。

    close(0)close(1)close(2)
    • 1
    • 2
    • 3

    (6)其他:忽略SIGCHLD信号

    signal(SIGCHLD,SIG_IGN);

    #include<stdio.h>
    #include<unistd.h>
    #include<signal.h>
    #include<stdlib.h>
    int creat_daemon()
    {  
        //(1)调用umask将文件模式创建屏蔽字设置为0.
        umask(0);    
       //(2)调用fork,父进程退出(exit)。  
        pid_t id = fork();
        if(id > 0)
        {
            exit(1);
        }
        else if(id == 0)
        {
            setsid();         //(3)创建一个新的会话
            if(chdir("/")<0)  //(4)将新建会话的工作目录改成根目录
            {
               perror("chdir");
               return;
            }
           //(5)关闭从父进程继承来的文件
            close(0);
            //close(1); 假如这里没有关闭会出现什么情况,看下面结果
            close(2);
           //(6)忽略SIGCHLD信号。
            signal(SIGCHLD, SIG_IGN);
     
        }
    }
    
    int main()
    {
        creat_daemon();
        while(1);
        return 0;
    }
    


    由上图可知通过运行自己编写的mydaemon在Linux后台创建了一个守护进程,它的父进程是1号进程,它自己是自成进程组,自成会话的。

    在Linux的根目录下有一个目录proc,/proc目录中包含许多以数字命名的子目录,这些数字表示系统当前正在运行进程的进程号,里面包含对应进程相关的多个信息文件。例如 cd /proc/18225,进入到刚才创建的守护进程的id里面,并查看它进程id所对应的文件描述符fd的情况。


    可以发现当1号文件描述符不关闭的时候,此时的1号文件描述符指向的是自己的特殊的设备文件/dev/pts/1。所以在创建守护进程的时候就是有一个步骤要关闭不必要的文件描述符。  


    方式二:创建守护进程也可以调用daemon函数:int daemon(int nochdir, int noclose); 

    一般调用daemon有两种方式:
    1).daemon(0,0); //默认更改工作目录且更改文件描述符0,1,2为空,使其指向/dev/null。这个/dev/null就类似黑洞,不管哪个文件描述符对其进行写操作,它都会直接将数据丢弃;
    2).daemon(1,0); //不更改工作目录也不更改文件描述符;


    守护进程要fork两次的原因:

    第一次fork:这里第一次fork的作用就是让shell认为这条命令已经终止,不用挂在终端输入上;再一个是为了后面的setsid服务,因为调用setsid函数的进程不能是进程组组长,如果不fork子进程,那么此时的父进程是进程组组长,无法调用setsid。所以到这里子进程便成为了一个新会话组的组长。


    第二次fork:第2次fork不是必须的。也看到很多开源服务没有fork第二次。fork第二次主要目的是。防止进程再次打开一个控制终端。因为打开一个控制终端的前台条件是该进程必须是会话组长。再fork一次,子进程ID != sid(sid是进程父进程的sid)。所以也无法打开新的控制终端。

    daemon目的就是防止终端产生的一些信号让进程退出。上面函数并没有直接调用signal函数去处理它。而是间接通过fork和setsid函数使用更少代码优雅处理。而被有些人误以为是防止父进程没有正常退出而导致的僵死进程的原因需要这样处理。

      

    展开全文
  • Linux入门:创建守护进程

    千次阅读 2017-06-07 16:39:50
    创建守护进程(fork一次与fork两次)
  • Linux中创建守护进程setsid()

    千次阅读 2020-04-11 15:48:17
    文章目录编程环境:守护进程的特点:进程组 - 多个进程:会话 - 多个进程组:创建守护进程模型:写一个例子:文件掩码是什么?下载地址: 简 述: 前面几篇,刚写过了父子进程的实例。这里写一个守护进程 的例子,...
  • Linux创建守护进程

    2013-08-07 22:52:37
    创建守护进程 创建子进程,父进程退出  这是编写守护进程的第一步。由于守护进程是脱离控制终端的,因此,完成第一步后就会在Shell终端里造成一程序已经运行完毕的假象。之后的所有工作都在子进程中完成,而用户...
  • 【C++】创建守护进程守护进程C++代码 原本是计划把C++服务器的内容一起写出来,但是由于我写博速度还是太慢,所以这次先把我每次服务器开发都要遇到的第一步——守护进程的内容整理出来。以下内容结合了网上各种...
  • 创建守护进程的步骤

    万次阅读 多人点赞 2018-08-03 21:30:55
    什么是守护进程? 答:守护进程是后台运行的、系统启动是就存在的、不予任何终端关联的,用于处理一些系统级别任务的特殊进程。...根据上述的特性,我们便可以创建一个简单的守护进程,这里以 Linux 系统下从终...
  • 创建守护进程关键步骤

    千次阅读 2020-08-25 22:22:45
    创建一个守护进程,有几个关键的步骤,也有几个地方需要注意,几个关键的步骤有:1:清除文件创建权限2:调用fork,然后使父进程退出3:调用setsid以创建一个新的会话4:切换工作目录5:关闭不需要的文件描述符 ...
  • linux之创建守护进程

    千次阅读 2016-10-17 17:48:49
    其实,本质上守护进程和普通的进程并没有什么区别,只是我们规定了一种进程的编写规则,将其叫做守护进程,仅此而已。 特点1. 在后台运行 为了不让其阻塞终端,我们用fork()创建子进程,然后退出父进程,就可以...
  • 守护进程概念,以及怎么创建守护进程

    万次阅读 多人点赞 2016-10-09 20:32:30
    一,守护进程概述 Linux Daemon(守护进程)是运行在后台的一种特殊进程。它独立于控制终端并且周期性地执行某种任务或等待处理某些发生的事件。它不需要用户输入就能运行而且提供某种服务,不是对整个系统就是对...
  • 守护进程介绍 Daemon()程序是一直运行的服务端程序,又称为守护进程。通常在系统后台运行,没有控制终端,不与前台交互,Daemon程序一般作为系统服务使用。Daemon是长时间运行的进程,通常在系统启动后就运行,在...
  • 原文:... 要把最后一个wait()的进程设为守护进程 参见英文答案 >What is Daemon thread in Java?2 我不明白守护进程线程的用法和目的。 ...此外,我试图创建守护进程,但我...
  • 如何创建守护进程

    2015-09-10 23:00:42
    守护进程  在linux或者unix操作系统中在系统的引导的时候会开启很多服务,这些服务就叫做守护进程。为了增加灵活性,root可以选择系统开启的模式,这些模式叫做运行级别,每一种运行级别以一定的方式配置系统。 ...
  • python创建守护进程

    千次阅读 2019-06-18 01:06:41
    # description: 一个守护进程的简单包装类, 具备常用的start|stop|restart|status功能, 使用方便 # 需要改造为守护进程的程序只需要重写基类的run函数就可以了 # date: 2015-10-29 # usage: 启动: python daemon...
  • linux创建守护进程

    千次阅读 2014-10-12 12:27:40
     linux开启进程都是与终端绑定的,终端一关,进程也关,如果想独立不受干扰,必须将此进程变为守护进程(在后台运行,不以终端方式与用户交互)。 守护进程能够突破这种限制,它从被执行开始运转,直到整个系统...
  • Linux编程技术详解-创建守护进程由于守护进程的特点,编写守护进程程序必须遵守一定的规则。本节将阐述这些规则的要点,并给出相关代码。8.2.1 实现守护进程的步骤在Linux系统中,要编程实现一个守护进程必须遵守...
  • 我们先来了解一下什么是守护进程守护进程也称精灵进程(Daemon),是运行在后台的一种特殊进程。它独立于控制终端并且周期性地执行某种任务或等待处理某些发生的事件。守护进程是生存期长的一种进程。它们常常在...
  • 在unix系统中创建守护进程  守护进程是生存期长的一种进程。它们独立于控制终端并且周期性的执行某种任务或等待处理某些发生的事件。他们常常在系统引导装入时启动,在系统关闭时终止。unix系统有很多守护...
  • 守护进程守护进程是生存期长的一种进程。 常常在系统引导装入时启动。 它们无控制终端,故称之后台运行。为什么要引入守护进程?由于在linux中,每一个系统与用户进行交流的界面称为终端,每一个从此终端开始运行...
  • 创建守护进程 daemon

    2012-12-26 15:09:11
    在后台一直运行的进程为守护进程。  建立守护进程的5个步骤: 1,fork()创建子进程后,父进程立即退出。这样子进程就变为孤儿进程。 2,调用setsid():是创建的进程脱离控制终端,同时创建新的 进程组,使得新...
  • Linux系统下创建守护进程(Daemon)

    万次阅读 2018-07-30 17:29:50
    守护进程(daemon)是指在后台运行的,没有控制终端与之相连的进程。它独立于控制终端,周期性地执行某种任务。Linux的大多数服务器就是用守护进程的方式实现的。如web服务器进程http等。守护进程在后台运行,类似于...
  • 我们先来了解一下什么是守护进程守护进程 守护进程也称精灵进程(Daemon) 它是运⾏在后台的⼀种特殊进程。它独⽴于控制终端并且周期性地执⾏某种任务或等待处理某些发⽣的事件。守护进程是⼀种很有⽤的进程。...
  • 1,进程的概念:程序的一次动态执行过程。  进程存在于内存当中,存在着 创建,调度,执行和消亡,进程号是进程的唯一标志,每一个进程都有自己独立的内存空间,... 2,进程的类型:交互进程,批处理进程,守护进程
  • 调用fork创建进程,关闭父进程,子进程的父进程变为init,完成这一步后就在shell终端造成程序已经运行完毕的假象,之后的工作在子进程执行,用户在shell终端与可以执行其他命令,程序在后台运行。 调用setsid,让...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 132,166
精华内容 52,866
关键字:

创建守护进程