php守护进程

来源:互联网 发布:白熊事务所装软件 编辑:程序博客网 时间:2024/05/18 01:11

注:转载自

http://blog.csdn.net/phpkernel/article/details/6458991

守护进程也称精灵进程(daemon),是生存期较长的一种进程。它们常常用在系统自举时启动,仅在系统关闭时才终止。因为它们没有控制终端,所以说它们是在后台运行的。UNIX类操作系统有很多的守护进程,它们执行日常事务活动。

目前有大量的web站点基与PHP开发,业务逻辑都是由PHP来实现,很多时候我们也需要一个PHP的daemon来做一些日常事务,例如我们想每隔一个小时统计一下数据库中的某项数据,每天定期的执行一些备份或则监控任务。这些任务在apache模块的web环境下实现比较困难而且容易引发很多问题。

这里我介绍一款我自己写的PHP5版的daemon类 - KalonDaemon.   ^_^  现在和大家一起分享。

概要:
    KalonDaemon是一款PHP5的daemon类,我们在PHP代码中可以直接包含并且使用,KalonDaemon工作在cli sapi下( command line interface),它能把一个普通的PHP进程变成一个守护进程。
使用方式:
  在PHP脚本中包含了KalonDaemon设置好参数然后调用start()方法。然后我们在命令行下用PHP cli执行脚本,比如cli sapi路径为 /usr/local/bin/php,   我们编写的程序路径 /home/test/mydaemon.php,那么我们用以下方式运行程序:          /usr/local/bin/php  /home/test/mydaemon.php   根据需要可以在后面添加别的参数。
工作流程:
KalonDaemon遵循大部分unix类系统下的守护进程编程规则,主要工作流程如下:
1. 调用pcntl_fork,然后使父进程退出(exit).这样做实现如下几点:

第一,如果该守护进程是作为一条shell命令启动,那么父进程终止使得 shell认为这条命令已经执行完毕;

第二,子进程继承父进程的进程组ID,但是具有一个新的进程ID,这就保证了子进程不是一个进程组的组长,这对于下面要做的posix_setsid调用是必要的前提条件。
2.调用posix_setsid以创建一个新的会话,这样新进程就成为了新会话的首进程,同时是新进程组的组长进程,而且没有控制终端。
3.设置进程信号回调函数,方便我们用其它进程对守护进程进行控制。

 

以下是mydaemon.php的源码:

 

[php] view plaincopy
  1. <?php  
  2. require_once './KalonDaemon.php';  
  3. declare(ticks = 1);  
  4. $toDo = $_SERVER['argv'][1];  
  5. $daemonConf = array('pidFileName' => 'mydaemon.pid',  
  6.                     'verbose'     => true);  
  7. function myHandler1()  
  8. {  
  9.     sleep(5);  
  10.     echo "This handler1 works./n";  
  11. }  
  12. function myHandler2()  
  13. {  
  14.    echo "This handler2 works./n";  
  15. }  
  16. try {  
  17.     $daemon = new KalonDaemon($daemonConf);  
  18.     if ($toDo == 'start') {  
  19.         $daemon->addSignalHandler(SIGUSR1, 'myHandler1');  
  20.         $daemon->addSignalHandler(SIGUSR2, 'myHandler2');  
  21.         $daemon->start();  
  22.         for (;;) {  
  23.             echo "running./n";  
  24.             sleep(1000);  
  25.         }  
  26.     } elseif ($toDo == 'stop') {  
  27.         $daemon->stop();  
  28.     } else {  
  29.         die("unknown action.");  
  30.     }  
  31. } catch (KalonDaemonException $e) {  
  32.     echo $e->getMessage();  
  33.     echo "/n";  
  34. }  
  35. ?>  

 

在命令行下执行:

/path/to/phpcli/php  mydaemon.php start

 

输出如下信息:

Daemon started with pid 8976...
running.

说明守护进程已经开始运行,进程号为8976,当然一般情况进程号每次都会不一样。

 

由于mydaemon.php中有一个死循环,每次循环会睡眠1000秒,所以进程永远不会终止。

mydaemon.php中为守护进程注册了两个信号句柄,信号SIGUSR1对应函数myHandler1(), 信号SIGUSR2对应myHandler2(),我们可以通过kill命令给进程发送这两个信号来唤醒进程。

 

kill -SIGUSR2 8976

输出信息如下:

This handler2 works.
running.

说明睡眠中的进程被唤醒,并且执行了myHandler2()函数,然后再次进入了循环。

 

 

当我们需要终止守护进程的时候,可以用以下命令:

/path/to/phpcli/php  mydaemon.php stop

输出信息如下:

Daemon stopped with pid 8976...

这样守护进程就终止了。

 

这样的特性可以在某些应用场景非常有用,比如服务器在接受到一些上传的数据之后,需要唤醒守护进程来处理这些数据。守护进程可以长期出去睡眠状态等待,当数据到来之后,发送信号唤醒守护进程,守护进程马上开始处理这些数据。这样要比定期的轮询效率高很多,而且不会有延迟现象。

 

 

KalonDaemon.php

[php] view plaincopy
  1. <?php  
  2. /** 
  3.  * Kalon Daemon -> A Unix Daemon for PHP5 
  4.  *     This is a free daemon tool, you can use it anyway you like. 
  5.  *  
  6.  * NOTICE: 
  7.  * 1:This tool must run in cli sapi, any other sapis will cause a  
  8.  *   KalonDaemonException thrown.so you need to use this tool in a 
  9.  *   command line interface,command such as: /path/to/php mydaemon.php 
  10.  *  
  11.  * 2:Daemon needs pcntl and posix extension support. Make sure your cli 
  12.  *   sapi has loaded these two extension.The posix is compiled in php by 
  13.  *   default, while pcntl must be compiled or dynamic load by yourself. 
  14.  *   Missing anyone of these extension will cause a KalonDaemonException  
  15.  *   thrown. 
  16.  *  
  17.  * USAGE: 
  18.  *  
  19.  *put the code below in mydaemon.php  
  20.  *  
  21. require_once '/path/to/KalonDaemon.php'; 
  22. declare(ticks = 1); 
  23. $toDo = $_SERVER['argv'][1]; 
  24. $daemonConf = array('pidFileName' => 'mydaemon.pid', 
  25.                     'verbose'     => true); 
  26. function myHandler1() 
  27. { 
  28.     sleep(5); 
  29.     echo "This handler1 works./n"; 
  30. } 
  31. function myHandler2() 
  32. { 
  33.    echo "This handler2 works./n"; 
  34. } 
  35. try { 
  36.     $daemon = new KalonDaemon($daemonConf); 
  37.     if ($toDo == 'start') { 
  38.         $daemon->addSignalHandler(SIGUSR1, 'myHandler1'); 
  39.         $daemon->addSignalHandler(SIGUSR2, 'myHandler2'); 
  40.         $daemon->start(); 
  41.         for (;;) { 
  42.             echo "running./n"; 
  43.             sleep(1000); 
  44.         } 
  45.     } elseif ($toDo == 'stop') { 
  46.         $daemon->stop(); 
  47.     } else { 
  48.         die("unknown action."); 
  49.     } 
  50. } catch (KalonDaemonException $e) { 
  51.     echo $e->getMessage(); 
  52.     echo "/n"; 
  53. } 
  54.  *  
  55.  * then open a command shell: 
  56.  * start daemon: 
  57.  * /path/to/phpcli/php /path/to/mydaemon.php start 
  58.  *  
  59.  * stop daemon: 
  60.  * /path/to/phpcli/php /path/to/mydaemon.php stop 
  61.  *  
  62.  *  
  63.  *  
  64.  * @author 玉面修罗  - Kalon 
  65.  * @version 1.0 
  66.  * @site: http://blog.csdn.net/phpkernel 
  67.  * E-mail/MSN: xiuluo-999@163.com 
  68.  */  
  69.   
  70.   
  71. class KalonDaemon   
  72. {  
  73.     /** 
  74.      * path of pid file 
  75.      * 
  76.      * @var string 
  77.      */  
  78.     private $_pidFilePath = "/var/run";  
  79.       
  80.     /** 
  81.      * name of pid file 
  82.      * 
  83.      * @var string 
  84.      */  
  85.     private $_pidFileName = "daemon.pid";  
  86.       
  87.     /** 
  88.      * out put run information 
  89.      * 
  90.      * @var boolean 
  91.      */  
  92.     private $_verbose = false;  
  93.       
  94.     /** 
  95.      * default singleton model 
  96.      * 
  97.      * @var boolean 
  98.      */  
  99.     private $_singleton = true;   
  100.       
  101.     /** 
  102.      * close file handle STDIN STDOUT STDERR 
  103.      * NOTICE: we do not close STDIN STDOUT STDERR indeed for some reason.  
  104.      * @var boolean 
  105.      */  
  106.     private $_closeStdHandle = true;  
  107.       
  108.     /** 
  109.      * pid of daemon 
  110.      * 
  111.      * @var int 
  112.      */  
  113.     private $_pid = 0;  
  114.       
  115.     /** 
  116.      * exec file  
  117.      * 
  118.      * @var string 
  119.      */  
  120.     private $_execFile = "";  
  121.       
  122.   
  123.     /** 
  124.      * function handlers for signal number 
  125.      * 
  126.      * @var array 
  127.      */  
  128.     private $_signalHandlerFuns = array();  
  129.   
  130.       
  131.     /** 
  132.      * set config 
  133.      * 
  134.      * @param array $configs 
  135.      */  
  136.     public function __construct($configs = array())  
  137.     {     
  138.         //load config  
  139.         if (is_array($configs))  
  140.             $this->setConfigs($configs);  
  141.     }  
  142.       
  143.     /** 
  144.      * pctntl is needed,and only works in cli sapi 
  145.      */  
  146.     public function _checkRequirement()  
  147.     {  
  148.         //check if pctnl loaded  
  149.         if (!extension_loaded('pcntl'))  
  150.             throw new KalonDaemonException("daemon needs support of pcntl extension, please enable it.");  
  151.   
  152.         //check sapi name,only for cli      
  153.         if ('cli' != php_sapi_name())  
  154.             throw new KalonDaemonException("daemon only works in cli sapi.");      
  155.     }  
  156.       
  157.     /** 
  158.      * set configs 
  159.      * pidFilePath: path of pid file 
  160.      * pidFileName: name of pid file 
  161.      * verbose    : output process information 
  162.      * singleton  : singleton model,only one instance of daemon at one time 
  163.      * closeStdHandle : close STDIN STDOUT STDERR when daemon run success 
  164.      *  
  165.      * @param array $configs 
  166.      */  
  167.     public function setConfigs($configs)  
  168.     {  
  169.         foreach ((array$configs as $item => $config) {  
  170.             switch ($item) {  
  171.                 case "pidFilePath":  
  172.                     $this->setPidFilePath($config);  
  173.                     break;  
  174.                 case "pidFileName":  
  175.                     $this->setPidFileName($config);  
  176.                     break;  
  177.                  case "verbose":  
  178.                     $this->setVerbose($config);  
  179.                     break;  
  180.                  case "singleton":  
  181.                     $this->setSingleton($config);  
  182.                     break;  
  183.                  case "closeStdHandle";  
  184.                     $this->setCloseStdHandle($config);   
  185.                     break;                                          
  186.                 default:  
  187.                     throw new KalonDaemonException("Unknown config item {$item}");  
  188.                     break;  
  189.             }  
  190.         }  
  191.     }  
  192.       
  193.     /** 
  194.      * set Pid File Path 
  195.      * 
  196.      * @param  string $path 
  197.      * @return boolean 
  198.      */  
  199.     public function setPidFilePath($path)  
  200.     {  
  201.         if (empty($path))  
  202.             return false;  
  203.               
  204.         if(!is_dir($path))  
  205.             if (!mkdir($path, 0777))  
  206.                 throw new KalonDaemonException("setPidFilePath: cannnot make dir {$path}.");  
  207.   
  208.         $this->_pidFilePath = rtrim($path"/");  
  209.         return true;      
  210.     }  
  211.       
  212.     /** 
  213.      * get Pid File Path 
  214.      * 
  215.      * @return string 
  216.      */  
  217.     public function getPidFilePath()  
  218.     {  
  219.         return $this->_pidFilePath;  
  220.     }  
  221.       
  222.     /** 
  223.      * set Pid File Name 
  224.      * 
  225.      * @param string $name 
  226.      * @return boolean 
  227.      */  
  228.     public function setPidFileName($name)  
  229.     {  
  230.         if (empty($name))  
  231.             return false;  
  232.           
  233.         $this->_pidFileName = trim($name);  
  234.         return true;      
  235.     }  
  236.       
  237.     /** 
  238.      * get Pid File Name 
  239.      * 
  240.      * @return string 
  241.      */  
  242.     public function getPidFileName()  
  243.     {  
  244.         return $this->_pidFileName;  
  245.     }  
  246.       
  247.     /** 
  248.      * set Open Output 
  249.      *    if sets to true,daemon will output start and stop information ,etc 
  250.      *  
  251.      * @param  boolean $open 
  252.      * @return boolean 
  253.      */  
  254.     public function setVerbose($open = true)  
  255.     {  
  256.         $this->_verbose = (boolean) $open;  
  257.         return true;  
  258.     }  
  259.       
  260.     /** 
  261.      * get Open Output 
  262.      * 
  263.      * @return boolean 
  264.      */  
  265.     public function getVerbose()  
  266.     {  
  267.         return $this->_verbose;  
  268.     }  
  269.       
  270.     /** 
  271.      * set Singleton 
  272.      *     if sets to true, daemon will keep singleton,which means that there is only one  
  273.      * instance of daemon at one time.     
  274.      *  
  275.      * @param  boolean $singleton 
  276.      * @return boolean 
  277.      */  
  278.     public function setSingleton($singleton = true)  
  279.     {  
  280.         $this->_singleton = (boolean) $singleton;  
  281.         return true;  
  282.     }  
  283.       
  284.     /** 
  285.      * get Singleton 
  286.      * 
  287.      * @return boolean 
  288.      */  
  289.     public function getSingleton()  
  290.     {  
  291.         return $this->_singleton;  
  292.     }  
  293.       
  294.     /** 
  295.      * set Close Std Handle 
  296.      * 
  297.      * @param  boolean $close 
  298.      * @return boolean 
  299.      */  
  300.     public function setCloseStdHandle($close = true)  
  301.     {  
  302.         $this->_closeStdHandle = (boolean) $close;  
  303.         return true;  
  304.     }  
  305.       
  306.     /** 
  307.      * get Close Std Handle 
  308.      * 
  309.      * @return boolean 
  310.      */  
  311.     public function getCloseStdHandle()  
  312.     {  
  313.         return $this->_closeStdHandle;  
  314.     }  
  315.       
  316.     /** 
  317.      * start daemon 
  318.      * 1.daemonize  
  319.      * 2.setup signal handlers 
  320.      * 3.close STDIN STDOUT STDERR 
  321.      *  
  322.      * @return boolean 
  323.      */  
  324.     public function start()  
  325.     {  
  326.         //this line used to put in the __construct,for some reason I move it here.  
  327.         $this->_checkRequirement();  
  328.           
  329.         //do daemon  
  330.         $this->_daemonize();  
  331.    
  332.         //default handler for stop  
  333.         if(!pcntl_signal(SIGTERM,  array($this,"signalHandler")))  
  334.             throw new KalonDaemonException("Cannot setup signal handler for signo {$signo}");       
  335.           
  336.           
  337.         //close file handle STDIN STDOUT STDERR  
  338.         //notic!!!This makes no use in PHP4 and some early version of PHP5  
  339.         //if we close these handle without dup to /dev/null,php process will die   
  340.         //when operating on them.  
  341.         if ($this->_closeStdHandle) {  
  342.             //fclose(STDIN);  
  343.             //fclose(STDOUT);  
  344.             //fclose(STDERR);  
  345.         }  
  346.           
  347.         return true;  
  348.     }  
  349.       
  350.     /** 
  351.      * stop daemon 
  352.      * 1.get daemon pid from pid file 
  353.      * 2.send signal to daemon 
  354.      *  
  355.      * @param  boolean $force  kill -9 or kill 
  356.      * @return boolean 
  357.      */  
  358.     public function stop($force = false)  
  359.     {  
  360.         if ($force)   
  361.             $signo = SIGKILL; //kill -9  
  362.         else    
  363.             $signo = SIGTERM; //kill   
  364.                   
  365.         //only use in singleton model      
  366.         if (!$this->_singleton)  
  367.             throw new KalonDaemonException("'stop' only use in singleton model.");  
  368.                      
  369.         if (false === ($pid = $this->_getPidFromFile()))  
  370.             throw new KalonDaemonException("daemon is not running,cannot stop.");  
  371.           
  372.         if (!posix_kill($pid$signo)) {  
  373.             throw new KalonDaemonException("Cannot send signal $signo to daemon.");   
  374.         }  
  375.           
  376.         $this->_unlinkPidFile();  
  377.           
  378.         $this->_out("Daemon stopped with pid {$pid}...");  
  379.         return true;  
  380.     }  
  381.       
  382.     /** 
  383.      * restart daemon 
  384.      */  
  385.     public function restart()  
  386.     {  
  387.         $this->stop();  
  388.         //sleep to wait  
  389.         sleep(1);  
  390.           
  391.         $this->start();  
  392.     }  
  393.           
  394.     /** 
  395.      * get daemon pid 
  396.      * @return int 
  397.      */  
  398.     public function getDaemonPid()  
  399.     {  
  400.         return $this->_getPidFromFile();  
  401.     }  
  402.       
  403.     /** 
  404.      * signalHander for dameon 
  405.      * 
  406.      * @param int $signo 
  407.      */  
  408.     public function signalHandler($signo)  
  409.     {     
  410.         $signFuns = $this->_signalHandlerFuns[$signo];  
  411.         if (is_array($signFuns)) {  
  412.             foreach ($signFuns as $fun) {  
  413.                 call_user_func($fun);  
  414.             }  
  415.         }  
  416.           
  417.         //default action  
  418.         switch ($signo) {  
  419.             case SIGTERM:  
  420.                 exit;  
  421.                 break;  
  422.             default:  
  423.                 // handle all other signals  
  424.         }         
  425.           
  426.     }  
  427.       
  428.     public function addSignalHandler($signo$fun)  
  429.     {  
  430.         if (is_string($fun)) {  
  431.             if (!function_exists($fun)) {  
  432.                 throw new KalonDaemonException("handler function {$fun} not exists");  
  433.             }  
  434.         }elseif (is_array($fun)) {  
  435.             if (!@method_exists($fun[0], $fun[1])) {  
  436.                 throw new KalonDaemonException("handler method not exists");  
  437.             }      
  438.         } else {  
  439.             throw new KalonDaemonException("error handler.");  
  440.         }  
  441.   
  442.         if(!pcntl_signal($signo,  array($this,"signalHandler")))  
  443.                 throw new KalonDaemonException("Cannot setup signal handler for signo {$signo}");  
  444.   
  445.         $this->_signalHandlerFuns[$signo][] = $fun;  
  446.         return $this;      
  447.     }  
  448.       
  449.     public function sendSignal($signo)  
  450.     {  
  451.         if (false === ($pid = $this->_getPidFromFile()))  
  452.             throw new KalonDaemonException("daemon is not running,cannot send signal.");  
  453.           
  454.         if (!posix_kill($pid$signo)) {  
  455.             throw new KalonDaemonException("Cannot send signal $signo to daemon.");   
  456.         }  
  457.           
  458.         //$this->_out("Send signal $signo to pid $pid...");  
  459.         return true;  
  460.     }  
  461.       
  462.     /** 
  463.      * daemon is active? 
  464.      * @return boolean 
  465.      */  
  466.     public function isActive()  
  467.     {  
  468.         try {  
  469.             $pid = $this->_getPidFromFile();  
  470.         } catch (KalonDaemonException $e) {  
  471.             return false;  
  472.         }  
  473.         if (false === $pid)  
  474.             return false;  
  475.               
  476.         if (false === ($active = @pcntl_getpriority($pid)))  
  477.             return false;  
  478.         else  
  479.             return true;  
  480.     }  
  481.       
  482.       
  483.     /** 
  484.      * daemonize  
  485.      * 1.check running , if singaleton model 
  486.      * 2.forck process 
  487.      * 3.detach from controlling terminal 
  488.      * 4.log pid 
  489.      *  
  490.      * @return boolean 
  491.      */  
  492.     private function _daemonize()  
  493.     {  
  494.         //single model, first check if running  
  495.         if ($this->_singleton) {  
  496.             $isRunning  = $this->_checkRunning();  
  497.             if ($isRunning)   
  498.                 throw new KalonDaemonException("Daemon already running");  
  499.         }  
  500.           
  501.         //fork current process  
  502.         $pid = pcntl_fork();  
  503.           
  504.         if ($pid == -1) {  
  505.             //fork error  
  506.             throw new KalonDaemonException("Error happened while fork process");  
  507.         } elseif ($pid) {  
  508.             //parent exit  
  509.             exit();  
  510.         } else {  
  511.             //child, get pid  
  512.             $this->_pid = posix_getpid();  
  513.         }  
  514.           
  515.         $this->_out("Daemon started with pid {$this->_pid}...");  
  516.           
  517.         //detach from controlling terminal  
  518.         if (!posix_setsid())  
  519.             throw new KalonDaemonException("Cannot detach from terminal");   
  520.           
  521.         //log pid in singleton model      
  522.         if ($this->_singleton)     
  523.             $this->_logPid();  
  524.           
  525.         return $this->_pid;  
  526.     }  
  527.       
  528.     /** 
  529.      * get Pid From File 
  530.      * 
  531.      * @return int 
  532.      */  
  533.     private function _getPidFromFile()  
  534.     {  
  535.         //if is set  
  536.         if ($this->_pid)  
  537.             return (int)$this->_pid;  
  538.               
  539.         $pidFile = $this->_pidFilePath . "/" . $this->_pidFileName;  
  540.         //no pid file,it's the first time of running  
  541.         if (!file_exists($pidFile))  
  542.             return false;  
  543.               
  544.         if (!$handle = fopen($pidFile"r"))   
  545.             throw new KalonDaemonException("Cannot open pid file {$pidFile} for read");   
  546.   
  547.         if (($pid = fread($handle, 1024)) === false)   
  548.             throw new KalonDaemonException("Cannot read from pid file {$pidFile}");   
  549.       
  550.         fclose($handle);  
  551.           
  552.         return $this->_pid = (int) $pid;  
  553.     }  
  554.       
  555.     /** 
  556.      * _checkRunning 
  557.      *  in singleton mode ,we check if daemon running 
  558.      *  
  559.      * @return boolean 
  560.      */  
  561.     private function _checkRunning()  
  562.     {  
  563.         $pid = $this->_getPidFromFile();  
  564.           
  565.         //no pid file,not running  
  566.         if(false === $pid)  
  567.             return false;  
  568.           
  569.         //get exe file path from pid  
  570.         switch(strtolower(PHP_OS))  
  571.         {  
  572.             case "freebsd":  
  573.                 $strExe = $this->_getFreebsdProcExe($pid);  
  574.                 if($strExe === false)  
  575.                     return false;  
  576.                 $strArgs = $this->_getFreebsdProcArgs($pid);  
  577.                 break;  
  578.                   
  579.             case "linux":  
  580.                 $strExe = $this->_getLinuxProcExe($pid);  
  581.                 if($strExe === false)  
  582.                     return false;  
  583.                 $strArgs = $this->_getLinuxProcArgs($pid);  
  584.                 break;  
  585.                   
  586.             default:  
  587.                 return false;  
  588.         }  
  589.           
  590.         $exeRealPath = $this->_getDaemonRealPath($strArgs$pid);  
  591.           
  592.         //get exe file path from command  
  593.         if ($strExe != PHP_BINDIR . "/php")  
  594.             return false;  
  595.            
  596.         $selfFile = "";  
  597.         $sapi = php_sapi_name();  
  598.         switch($sapi)  
  599.         {  
  600.             case "cgi":  
  601.             case "cgi-fcgi":  
  602.                 $selfFile = $_SERVER['argv'][0];  
  603.                 break;  
  604.             default:  
  605.                 $selfFile = $_SERVER['PHP_SELF'];  
  606.                 break;  
  607.         }  
  608.         $currentRealPath = realpath($selfFile);  
  609.           
  610.           
  611.         //compare two path  
  612.         if ($currentRealPath != $exeRealPath)  
  613.             return false;  
  614.         else   
  615.             return true;  
  616.     }  
  617.       
  618.     /** 
  619.      * log Pid 
  620.      */  
  621.     private function _logPid()  
  622.     {  
  623.         $pidFile = $this->_pidFilePath . "/" . $this->_pidFileName;  
  624.         if (!$handle = fopen($pidFile"w")) {  
  625.             throw new KalonDaemonException("Cannot open pid file {$pidFile} for write");   
  626.         }  
  627.         if (fwrite($handle$this->_pid) == false) {  
  628.             throw new KalonDaemonException("Cannot write to pid file {$pidFile}");   
  629.         }  
  630.         fclose($handle);  
  631.     }  
  632.       
  633.     /** 
  634.      * unlink pid file 
  635.      *    in singleton mode, unlink pid file while daemon stop 
  636.      *  
  637.      * @return boolean 
  638.      */  
  639.     private function _unlinkPidFile()  
  640.     {  
  641.         $pidFile = $this->_pidFilePath . '/' . $this->_pidFileName;  
  642.         return @unlink($pidFile);  
  643.     }  
  644.       
  645.     /** 
  646.      * get Daemon RealPath 
  647.      * 
  648.      * @param string $daemonFile 
  649.      * @param int    $daemonPid 
  650.      * @return string 
  651.      */  
  652.     private function _getDaemonRealPath($daemonFile$daemonPid)  
  653.     {  
  654.         $daemonFile = trim($daemonFile);  
  655.         if(substr($daemonFile,0,1) !== "/") {  
  656.             $cwd = $this->_getLinuxProcCwd($daemonPid);  
  657.             $cwd = rtrim($cwd"/");  
  658.             $cwd = $cwd . "/" . $daemonFile;  
  659.             $cwd = realpath($cwd);  
  660.             return $cwd;  
  661.         }  
  662.   
  663.         return realpath($daemonFile);  
  664.     }  
  665.       
  666.     /** 
  667.      * get Freebsd ProcExe 
  668.      * 
  669.      * @param  int $pid 
  670.      * @return string 
  671.      */  
  672.     private function _getFreebsdProcExe($pid)  
  673.     {  
  674.         $strProcExeFile = "/proc/" . $pid . "/file";  
  675.         if (false === ($strLink = @readlink($strProcExeFile))) {  
  676.             //throw new KalonDaemonException("Cannot read link file {$strProcExeFile}");  
  677.             return false;     
  678.         }  
  679.           
  680.         return $strLink;  
  681.     }  
  682.       
  683.     /** 
  684.      * get Linux Proc Exe 
  685.      * 
  686.      * @param  int    $pid 
  687.      * @return string 
  688.      */  
  689.     private function _getLinuxProcExe($pid)  
  690.     {  
  691.         $strProcExeFile = "/proc/" . $pid . "/exe";  
  692.         if (false === ($strLink = @readlink($strProcExeFile))) {  
  693.            //throw new KalonDaemonException("Cannot read link file {$strProcExeFile}");  
  694.             return false;   
  695.         }  
  696.           
  697.         return $strLink;  
  698.     }     
  699.       
  700.     /** 
  701.      * get Freebsd Proc Args 
  702.      * 
  703.      * @param   int    $pid 
  704.      * @return  string 
  705.      */  
  706.     private function _getFreebsdProcArgs($pid)  
  707.     {  
  708.         return $this->_getLinuxProcArgs($pid);  
  709.     }  
  710.       
  711.     /** 
  712.      * get Linux Proc Args 
  713.      * 
  714.      * @param   int  $pid 
  715.      * @return  string 
  716.      */  
  717.     private function _getLinuxProcArgs($pid)  
  718.     {  
  719.         $strProcCmdlineFile = "/proc/" . $pid . "/cmdline";  
  720.           
  721.         if (!$fp = @fopen($strProcCmdlineFile"r")) {  
  722.             throw new KalonDaemonException("Cannot open file {$strProcCmdlineFile} for read");  
  723.                   
  724.         }  
  725.         if (!$strContents = fread($fp, 4096)) {  
  726.              throw new KalonDaemonException("Cannot read or empty file {$strProcCmdlineFile}");   
  727.         }  
  728.         fclose($fp);  
  729.           
  730.         $strContents = preg_replace("/[^/w/.///-]/"" "  
  731.             , trim($strContents));  
  732.         $strContents = preg_replace("//s+/"" "$strContents);  
  733.           
  734.         $arrTemp = explode(" "$strContents);  
  735.         if(count($arrTemp) < 2) {  
  736.             throw new KalonDaemonException("Invalid content in {$strProcCmdlineFile}");   
  737.         }  
  738.           
  739.         return trim($arrTemp[1]);  
  740.     }  
  741.       
  742.     /** 
  743.      * get Linux Proc Cwd 
  744.      * 
  745.      * @param   int    $pid 
  746.      * @return  string 
  747.      */  
  748.     private function _getLinuxProcCwd($pid)  
  749.     {  
  750.         $strProcExeFile = "/proc/" . $pid . "/cwd";  
  751.         if (false === ($strLink = @readlink($strProcExeFile))) {  
  752.             throw new KalonDaemonException("Cannot read link file {$strProcExeFile}");    
  753.         }  
  754.           
  755.         return $strLink;  
  756.     }  
  757.       
  758.     /** 
  759.      * out put process info 
  760.      *   if open _openOutput 
  761.      *  
  762.      * @param  string $str 
  763.      * @return boolean 
  764.      */  
  765.     private function _out($str)  
  766.     {  
  767.         if ($this->_verbose) {  
  768.             fwrite(STDOUT, $str . "/n");  
  769.         }   
  770.         return true;      
  771.     }  
  772.       
  773. }  
  774.   
  775. /** 
  776.  * Exception for KalonDaemon 
  777.  */  
  778. class KalonDaemonException extends Exception   
  779. {  
  780.       
  781. }  
  782. ?> 
原创粉丝点击