亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 開發 > PHP > 正文

如何寫php守護進程(Daemon)

2024-05-04 23:41:44
字體:
來源:轉載
供稿:網友
這篇文章主要介紹了如何寫php守護進程Daemon,
 

守護進程(Daemon)是運行在后臺的一種特殊進程。它獨立于控制終端并且周期性地執行某種任務或等待處理某些發生的事件。守護進程是一種很有用的進程。php也可以實現守護進程的功能。
一、基本概念
進程: 每個進程都有一個父進程,子進程退出,父進程能得到子進程退出的狀態。
進程組每個進程都屬于一個進程組,每個進程組都有一個進程組號,該號等于該進程組組長的PID
二、守護編程要點
1. 在后臺運行     
         為避免掛起控制終端將Daemon放入后臺執行。方法是在進程中調用fork使父進程終止,讓Daemon在子進程中后臺執行。 if($pid=pcntl_fork()) exit(0);//是父進程,結束父進程,子進程繼續
2. 脫離控制終端,登錄會話和進程組 
       有必要先介紹一下Linux中的進程與控制終端,登錄會話和進程組之間的關系:進程屬于一個進程組,進程組號(GID)就是進程組長的進程號(PID)。登錄會話可以包含多個進程組。這些進程組共享一個控制終端。這個控制終端通常是創建進程的登錄終  端。 控制終端,登錄會話和進程組通常是從父進程繼承下來的。我們的目的就是要擺脫它們,使之不受它們的影響。方法是在第1點的基礎上,調用setsid()使進程成為會話組長: posix_setsid();
        說明:當進程是會話組長時setsid()調用失敗。但第一點已經保證進程不是會話組長。setsid()調用成功后,進程成為新的會話組長和新的進程組長,并與原來的登錄會話和進程組脫離。由于會話過程對控制終端的獨占性,進程同時與控制終端脫離。
3. 禁止進程重新打開控制終端
        現在,進程已經成為無終端的會話組長。但它可以重新申請打開一個控制終端。可以通過使進程不再成為會話組長來禁止進程重新打開控制終端: if($pid=pcntl_fork()) exit(0);//結束第一子進程,第二子進程繼續(第二子進程不再是會話組長)
4. 關閉打開的文件描述符
        進程從創建它的父進程那里繼承了打開的文件描述符。如不關閉,將會浪費系統資源,造成進程所在的文件系統無法卸下以及引起無法預料的錯誤。按如下方法關閉它們:
        fclose(STDIN),fclose(STDOUT),fclose(STDERR)關閉標準輸入輸出與錯誤顯示。
5. 改變當前工作目錄
        進程活動時,其工作目錄所在的文件系統不能卸下。一般需要將工作目錄改變到根目錄。對于需要轉儲核心,寫運行日志的進程將工作目錄改變到特定目錄如chdir("/")
6. 重設文件創建掩模
        進程從創建它的父進程那里繼承了文件創建掩模。它可能修改守護進程所創建的文件的存取位。為防止這一點,將文件創建掩模清除:umask(0);
7. 處理SIGCHLD信號
        處理SIGCHLD信號并不是必須的。但對于某些進程,特別是服務器進程往往在請求到來時生成子進程處理請求。如果父進程不等待子進程結束,子進程將成為僵尸進程(zombie)從而占用系統資源。如果父進程等待子進程結束,將增加父進程的負擔,影  響服務器進程的并發性能。在Linux下可以簡單地將SIGCHLD信號的操作設為SIG_IGN。 signal(SIGCHLD,SIG_IGN);
        這樣,內核在子進程結束時不會產生僵尸進程。這一點與BSD4不同,BSD4下必須顯式等待子進程結束才能釋放僵尸進程。關于信號的問題請參考Linux 信號說明列表
三、實例

<?php * 后臺腳本控制類 */ class DaemonCommand{     private $info_dir="/tmp";   private $pid_file="";   private $terminate=false; //是否中斷   private $workers_count=0;   private $gc_enabled=null;   private $workers_max=8; //最多運行8個進程     public function __construct($is_sington=false,$user='nobody',$output="/dev/null"){         $this->is_sington=$is_sington; //是否單例運行,單例運行會在tmp目錄下建立一個唯一的PID       $this->user=$user;//設置運行的用戶 默認情況下nobody       $this->output=$output; //設置輸出的地方       $this->checkPcntl();   }   //檢查環境是否支持pcntl支持   public function checkPcntl(){     if ( ! function_exists('pcntl_signal_dispatch')) {       // PHP < 5.3 uses ticks to handle signals instead of pcntl_signal_dispatch       // call sighandler only every 10 ticks       declare(ticks = 10);     }       // Make sure PHP has support for pcntl     if ( ! function_exists('pcntl_signal')) {       $message = 'PHP does not appear to be compiled with the PCNTL extension. This is neccesary for daemonization';       $this->_log($message);       throw new Exception($message);     }     //信號處理     pcntl_signal(SIGTERM, array(__CLASS__, "signalHandler"),false);     pcntl_signal(SIGINT, array(__CLASS__, "signalHandler"),false);     pcntl_signal(SIGQUIT, array(__CLASS__, "signalHandler"),false);       // Enable PHP 5.3 garbage collection     if (function_exists('gc_enable'))     {       gc_enable();       $this->gc_enabled = gc_enabled();     }   }     // daemon化程序   public function daemonize(){       global $stdin, $stdout, $stderr;     global $argv;       set_time_limit(0);       // 只允許在cli下面運行     if (php_sapi_name() != "cli"){       die("only run in command line mode/n");     }       // 只能單例運行     if ($this->is_sington==true){         $this->pid_file = $this->info_dir . "/" .__CLASS__ . "_" . substr(basename($argv[0]), 0, -4) . ".pid";       $this->checkPidfile();     }       umask(0); //把文件掩碼清0       if (pcntl_fork() != 0){ //是父進程,父進程退出       exit();     }       posix_setsid();//設置新會話組長,脫離終端       if (pcntl_fork() != 0){ //是第一子進程,結束第一子進程         exit();     }       chdir("/"); //改變工作目錄       $this->setUser($this->user) or die("cannot change owner");       //關閉打開的文件描述符     fclose(STDIN);     fclose(STDOUT);     fclose(STDERR);       $stdin = fopen($this->output, 'r');     $stdout = fopen($this->output, 'a');     $stderr = fopen($this->output, 'a');       if ($this->is_sington==true){       $this->createPidfile();     }     }   //--檢測pid是否已經存在   public function checkPidfile(){       if (!file_exists($this->pid_file)){       return true;     }     $pid = file_get_contents($this->pid_file);     $pid = intval($pid);     if ($pid > 0 && posix_kill($pid, 0)){       $this->_log("the daemon process is already started");     }     else {       $this->_log("the daemon proces end abnormally, please check pidfile " . $this->pid_file);     }     exit(1);     }   //----創建pid   public function createPidfile(){       if (!is_dir($this->info_dir)){       mkdir($this->info_dir);     }     $fp = fopen($this->pid_file, 'w') or die("cannot create pid file");     fwrite($fp, posix_getpid());     fclose($fp);     $this->_log("create pid file " . $this->pid_file);   }     //設置運行的用戶   public function setUser($name){       $result = false;     if (empty($name)){       return true;     }     $user = posix_getpwnam($name);     if ($user) {       $uid = $user['uid'];       $gid = $user['gid'];       $result = posix_setuid($uid);       posix_setgid($gid);     }     return $result;     }   //信號處理函數   public function signalHandler($signo){       switch($signo){         //用戶自定義信號       case SIGUSR1: //busy       if ($this->workers_count < $this->workers_max){         $pid = pcntl_fork();         if ($pid > 0){           $this->workers_count ++;         }       }       break;       //子進程結束信號       case SIGCHLD:         while(($pid=pcntl_waitpid(-1, $status, WNOHANG)) > 0){           $this->workers_count --;         }       break;       //中斷進程       case SIGTERM:       case SIGHUP:       case SIGQUIT:           $this->terminate = true;       break;       default:       return false;     }     }   /**   *開始開啟進程   *$count 準備開啟的進程數   */   public function start($count=1){       $this->_log("daemon process is running now");     pcntl_signal(SIGCHLD, array(__CLASS__, "signalHandler"),false); // if worker die, minus children num     while (true) {       if (function_exists('pcntl_signal_dispatch')){           pcntl_signal_dispatch();       }         if ($this->terminate){         break;       }       $pid=-1;       if($this->workers_count<$count){           $pid=pcntl_fork();       }         if($pid>0){           $this->workers_count++;         }elseif($pid==0){           // 這個符號表示恢復系統對信號的默認處理         pcntl_signal(SIGTERM, SIG_DFL);         pcntl_signal(SIGCHLD, SIG_DFL);         if(!empty($this->jobs)){           while($this->jobs['runtime']){             if(empty($this->jobs['argv'])){               call_user_func($this->jobs['function'],$this->jobs['argv']);             }else{               call_user_func($this->jobs['function']);             }             $this->jobs['runtime']--;             sleep(2);           }           exit();           }         return;         }else{           sleep(2);       }         }       $this->mainQuit();     exit(0);     }     //整個進程退出   public function mainQuit(){       if (file_exists($this->pid_file)){       unlink($this->pid_file);       $this->_log("delete pid file " . $this->pid_file);     }     $this->_log("daemon process exit now");     posix_kill(0, SIGKILL);     exit(0);   }     // 添加工作實例,目前只支持單個job工作   public function setJobs($jobs=array()){       if(!isset($jobs['argv'])||empty($jobs['argv'])){         $jobs['argv']="";       }     if(!isset($jobs['runtime'])||empty($jobs['runtime'])){         $jobs['runtime']=1;       }       if(!isset($jobs['function'])||empty($jobs['function'])){         $this->log("你必須添加運行的函數!");     }       $this->jobs=$jobs;     }   //日志處理   private function _log($message){     printf("%s/t%d/t%d/t%s/n", date("c"), posix_getpid(), posix_getppid(), $message);   }   }   //調用方法1 $daemon=new DaemonCommand(true); $daemon->daemonize(); $daemon->start(2);//開啟2個子進程工作 work();         //調用方法2 $daemon=new DaemonCommand(true); $daemon->daemonize(); $daemon->addJobs(array('function'=>'work','argv'=>'','runtime'=>1000));//function 要運行的函數,argv運行函數的參數,runtime運行的次數 $daemon->start(2);//開啟2個子進程工作   //具體功能的實現 function work(){    echo "測試1"; } ?> 

以上就是關于php守護進程的相關介紹,希望對大家的學習有所幫助。



注:相關教程知識閱讀請移步到PHP教程頻道。
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
日本精品视频在线观看| 成人中文字幕+乱码+中文字幕| 久久综合亚洲社区| 欧美视频在线免费| 国产精品视频免费在线观看| 成人国产在线激情| 亚洲精品久久久久久久久久久久久| 精品福利免费观看| 亚洲欧美精品中文字幕在线| 最新国产精品亚洲| 久久综合伊人77777尤物| 97碰碰碰免费色视频| 国产盗摄xxxx视频xxx69| 色老头一区二区三区在线观看| 亚洲黄色在线看| 欧美大片va欧美在线播放| 成人福利在线观看| 欧美激情精品久久久久久免费印度| 777国产偷窥盗摄精品视频| 亚洲欧美国产精品va在线观看| 成人黄色在线播放| 精品国产精品自拍| 韩国精品久久久999| 亚洲国产成人精品女人久久久| 国产精品h片在线播放| 午夜精品一区二区三区av| 亚洲香蕉成人av网站在线观看| 久久久日本电影| 九九热r在线视频精品| 久久成人免费视频| 国产一区二区黄| 国产香蕉精品视频一区二区三区| 亚洲视频日韩精品| 久久久精品欧美| 91欧美视频网站| 精品福利视频导航| 国产女人18毛片水18精品| 日韩av电影在线播放| 欧美亚洲激情视频| 欧美超级乱淫片喷水| 欧美巨乳美女视频| 久热精品在线视频| 少妇av一区二区三区| 日韩女在线观看| 不卡在线观看电视剧完整版| 欧美成人国产va精品日本一级| 欧日韩在线观看| 美女精品久久久| 午夜精品久久久久久99热软件| 欧美一级电影免费在线观看| 色婷婷综合久久久久中文字幕1| 欧美亚洲国产日韩2020| 亚洲精品乱码久久久久久金桔影视| 88国产精品欧美一区二区三区| 91精品久久久久久久久久久久久久| 一二美女精品欧洲| 精品久久香蕉国产线看观看亚洲| 国产精品视频一区二区高潮| 日本午夜在线亚洲.国产| 国产精品日韩在线| 国产精品久久久久久久久久免费| 九色精品免费永久在线| 精品一区二区三区三区| 狠狠综合久久av一区二区小说| 亚洲伊人久久综合| 日韩欧美成人网| 亚洲精品白浆高清久久久久久| 国产成人涩涩涩视频在线观看| 亚洲www永久成人夜色| 在线观看精品国产视频| 久久97久久97精品免视看| 国产精品免费视频久久久| 两个人的视频www国产精品| 欧美日韩美女在线| 国产亚洲精品久久久久久牛牛| 欧美性猛xxx| 欧美中文字幕视频| 中文字幕在线观看日韩| 中文字幕亚洲欧美日韩在线不卡| 国产精品视频久久久| 欧美成人h版在线观看| 精品亚洲国产成av人片传媒| 亚洲精品99久久久久中文字幕| 国产大片精品免费永久看nba| 欧美中文字幕在线视频| 97成人精品视频在线观看| 亚洲天天在线日亚洲洲精| 亚洲成年网站在线观看| 国产欧美婷婷中文| 成人国产精品一区二区| 久久久久久999| 亚洲欧美成人网| 色噜噜久久综合伊人一本| 欧美小视频在线观看| 国产91对白在线播放| 国产成人精品综合| 亚洲欧美视频在线| 欧美限制级电影在线观看| 欧美国产日韩一区二区| 黑人巨大精品欧美一区二区三区| 在线视频国产日韩| 国产精品亚洲欧美导航| 91精品在线观| 国产一区二区三区视频免费| 国产精品视频资源| 亚洲国产成人精品电影| 日韩av综合网| 国产在线视频不卡| 国产成人精品电影久久久| 一区二区福利视频| 国产精品亚洲一区二区三区| 国产日本欧美一区二区三区| 国产亚洲视频中文字幕视频| 亚洲一区二区三| 色综合导航网站| 久久国产精品电影| 成人av在线网址| 91香蕉国产在线观看| 国产精品久久久久久影视| 国产午夜精品视频| 中文字幕视频在线免费欧美日韩综合在线看| 国产精品69精品一区二区三区| 亚洲国产精品久久久久久| 久久久久久尹人网香蕉| 国产精品第3页| 久久中文字幕国产| 国产啪精品视频网站| 欧美大全免费观看电视剧大泉洋| 97久久超碰福利国产精品…| 日韩欧美在线网址| 91精品国产高清自在线| 日韩欧美在线视频日韩欧美在线视频| 中文字幕国内精品| 亚洲欧美自拍一区| 精品久久久久久久久久ntr影视| 九九九热精品免费视频观看网站| 亚洲福利在线观看| 亚洲精品国产精品国自产在线| 精品视频9999| 欧美日韩国产综合视频在线观看中文| 国产99久久精品一区二区| 欧洲中文字幕国产精品| 亚洲视频国产视频| 日韩中文字幕视频| 亚洲xxxxx电影| 一本色道久久88综合日韩精品| 久久视频在线观看免费| 国产精品视频区1| 国产亚洲aⅴaaaaaa毛片| 国产99久久精品一区二区| 国产精品7m视频| 欧美电影免费观看高清完整| 欧美日本高清视频| 91精品国产色综合久久不卡98口| 欧美精品久久久久久久久久| 欧美日韩美女在线| 国产精品久久久久av免费| 久久久久久久网站| 两个人的视频www国产精品| 欧美成人亚洲成人日韩成人| 国内免费精品永久在线视频| 国产一区二区三区久久精品| 国产美女91呻吟求| 久久久国产成人精品|