Chinaunix首页 | 论坛 | 博客
  • 博客访问: 4219663
  • 博文数量: 291
  • 博客积分: 8003
  • 博客等级: 大校
  • 技术积分: 4275
  • 用 户 组: 普通用户
  • 注册时间: 2010-10-30 18:28
文章分类

全部博文(291)

文章存档

2017年(1)

2013年(47)

2012年(115)

2011年(121)

2010年(7)

分类: Python/Ruby

2011-04-02 16:56:39

    运维需要对一些关键的服务进程进行守护,例如tomcat进程,mysql之类,这种进程没有自己的守护进程,而我们又不可能去改它们的源代码。
    为此我用perl写了一个守护进程,根据传入的命令,启动要守护的进程,若是进程挂了,则重新启动进程。
    即使子进程被杀死了,也能自动起来,但是程序有点缺陷:
1. 这个守护进程只是针对那些永远不退出的进程有效。
2. 若是杀死了守护进程,被守护的进程有可能不会退出,还要手动去杀死被守护进程,才能退出。因为我们找到杀死整个进程树的方法,
 
  1. #!/usr/bin/perl
  2. ####################################################
  3. #功能:实现把传入的命令执行,并守护,当命令被杀死了,能够重新启动命令
  4. #系统环境:centos 5
  5. #编译环境:perl, v5.8.8 built for i386-linux-thread-multi
  6. #执行:             
  7. #echo "i=0;" > /root/w.sh
  8. #echo 'while(true)' >> /root/w.sh
  9. #echo "do" >> /root/w.sh
  10. #echo ' echo $i;let i=$i+1;sleep 1;' >> /root/w.sh
  11. #echo 'done' >> /root/w.sh
  12. #perl deamon.pl "sh /root/w.sh >> /root/w.log"
  13. #
  14. ####################################################
  15. use POSIX ();
  16. use Carp;

  17. our $logfile="/tmp/deamon.log"; #输出日志
  18. our $child_pid; #记录子进程的id,以便父进程去杀死子进程
  19. our $parent_pid;#记录父进程的id,以便区分父子进程
  20. our $maxloop=10000; #放置大量产生子进程
  21. our $loop=0;
  22. our $CMD=$ARGV[0];
  23. if(!$CMD){
  24.     die("please input a cmd\n");
  25. }

  26. #杀死父子进程
  27. sub kill_pid{
  28.     logs("catch quit signal\n");
  29.     if($parent_pid){#判断是不是父进程
  30.         #父进程杀死所有的子进程
  31.         logs("parent kill child\n");
  32.         kill(15,$child_pid);
  33.         kill(15,-$$);
  34.         logs("parent quit\n");
  35.         exit 0;
  36.     }else{
  37.         #子进程退出
  38.         logs("child quit\n");        
  39.         exit 0;
  40.     }
  41. };
  42. $SIG{'INT'} = 'kill_pid'; # 中断退出
  43. $SIG{'TERM'} = 'kill_pid';
  44. $SIG{CHLD} = 'IGNORE'; # 忽略 SIGCHLD 信号,系统会自动回收结束的子进程
  45. #deamon方式
  46. daemonize();
  47. #启动服务
  48. logs("START deamon '$CMD'\n");

  49. while(1){
  50.     #防止输入的命令不是服务性命令,例如ls,执行很短时间的命令,或者后台执行的命令,这样最多会产生$maxloop个进程,不会把系统崩溃
  51.     $loop++;
  52.     if($loop>$maxloop){
  53.         exit 0;    
  54.     }
  55.     
  56.     #产生子进程
  57.     $child_pid=fork();
  58.     if (not defined $child_pid) {
  59.         print "cannot fork\n";
  60.         exit 0;
  61.     }
  62.     if($child_pid)
  63.     { # child >; 0, so we're the parent
  64.          $parent_pid=1;
  65.      logs("launching '$CMD'\n");
  66.      setpgrp(0, 0); #成为进程首领
  67.      wait();#等待子进程结束,若是结束则继续循环生成子进程
  68.     }else{
  69.             $parent_pid=0;
  70.             system($CMD);# child handles,子进程应该也是死循环的
  71.             logs("system return : $r ");
  72.      #执行命令非正常退出
  73.      if ($? == -1) {
  74.         logs("failed to execute: $! ");
  75.          }
  76.          elsif ($? & 127) {
  77.          logs("child died with signal",($? & 127),",",($? & 128) ? 'with' : 'without',' coredump');
  78.          }
  79.          else {
  80.          logs("child exited with value ",$? >> 8);
  81.              #若是$CMD正常退出的话,表示$CMD不是服务性程序
  82.                  logs("cannot deamon on '$CMD'");
  83.          }
  84.      #子进程退出    
  85.      exit 0;
  86.     }
  87. }

  88. #记录日志
  89. sub logs{
  90.     open(LOGFILE,">>$logfile") or die("cannot open $logfile");
  91.         my($sec,$min,$hour,$mday,$mon,$year)=localtime();
  92.     print LOGFILE sprintf("%04d-%02d-%02d %02d:%02d:%02d ",($year< 2000?($year+1900):$year),($mon+1),$mday,$hour,$min,$sec);
  93.     for my $msg (@_){
  94.         print LOGFILE $msg;
  95.     }
  96.     print LOGFILE "\n";
  97.     close(LOGFILE);
  98. }

  99. #deamon方式
  100. sub daemonize {

  101.         #    使当前进程对自己所写文件拥有完全控制权,避免继承的umask()设置带来困挠。这一步可选
  102.         umask(0);
  103.         #    关闭0、1、2三个句柄。许多daemon程序用sysconf()获取_SC_OPEN_MAX,并在一个偱环中关闭所有可能打开的文件句柄。目的在于释放不必要的系统资源,它们是有限资源。
  104.         close STDIN;
  105.         close STDOUT;
  106.         close STDERR;
  107.     chdir '/' or croak "Can't chdir to /: $!"; #减少管理员卸载(unmount)文件系统时可能遇上的麻烦。这一步可选,也可chdir()到其它目录。
  108.     open STDIN, '/dev/null' or croak "Can't read /dev/null: $!";
  109.     open STDOUT, '>/dev/null' or croak "Can't write to /dev/null: $!";
  110.     open STDERR, '>&STDOUT' or croak "Can't dup stdout: $!";
  111.     defined(my $pid = fork) or croak "Can't fork: $!";
  112.     exit if $pid;
  113.     #创建新的session和process group,成为其leader,并脱离控制终端。
  114.     setsid or croak "Can't start a new session: $!";
  115.     $SIG{CHLD} = 'IGNORE
阅读(4674) | 评论(0) | 转发(2) |
给主人留下些什么吧!~~