国产av日韩一区二区三区精品,成人性爱视频在线观看,国产,欧美,日韩,一区,www.成色av久久成人,2222eeee成人天堂

首頁 後端開發(fā) php教程 如何寫php守護進程(Daemon)_php技巧

如何寫php守護進程(Daemon)_php技巧

May 16, 2016 pm 08:01 PM
php 守護程式

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

<&#63;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;//設(shè)置運行的用戶 默認情況下nobody 
      $this->output=$output; //設(shè)置輸出的地方 
      $this->checkPcntl(); 
  } 
  //檢查環(huán)境是否支持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();//設(shè)置新會話組長,脫離終端 
  
    if (pcntl_fork() != 0){ //是第一子進程,結(jié)束第一子進程   
      exit(); 
    } 
  
    chdir("/"); //改變工作目錄 
  
    $this->setUser($this->user) or die("cannot change owner"); 
  
    //關(guān)閉打開的文件描述符 
    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是否已經(jīng)存在 
  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); 
  
  } 
  //----創(chuàng)建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); 
  } 
  
  //設(shè)置運行的用戶 
  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; 
  
  } 
  //信號處理函數(shù) 
  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; 
      //子進程結(jié)束信號 
      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 準(zhǔn)備開啟的進程數(shù) 
  */ 
  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){ 
  
        // 這個符號表示恢復(fù)系統(tǒng)對信號的默認處理 
        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("你必須添加運行的函數(shù)!"); 
    } 
  
    $this->jobs=$jobs; 
  
  } 
  //日志處理 
  private function _log($message){ 
    printf("%s\t%d\t%d\t%s\n", date("c"), posix_getpid(), posix_getppid(), $message); 
  } 
  
} 
  
//調(diào)用方法1 
$daemon=new DaemonCommand(true); 
$daemon->daemonize(); 
$daemon->start(2);//開啟2個子進程工作 
work(); 
  
  
  
  
//調(diào)用方法2 
$daemon=new DaemonCommand(true); 
$daemon->daemonize(); 
$daemon->addJobs(array('function'=>'work','argv'=>'','runtime'=>1000));//function 要運行的函數(shù),argv運行函數(shù)的參數(shù),runtime運行的次數(shù) 
$daemon->start(2);//開啟2個子進程工作 
  
//具體功能的實現(xiàn) 
function work(){ 
   echo "測試1"; 
} 
&#63;> 

以上就是關(guān)于php守護進程的相關(guān)介紹,希望對大家的學(xué)習(xí)有所幫助。

本網(wǎng)站聲明
本文內(nèi)容由網(wǎng)友自願投稿,版權(quán)歸原作者所有。本站不承擔(dān)相應(yīng)的法律責(zé)任。如發(fā)現(xiàn)涉嫌抄襲或侵權(quán)的內(nèi)容,請聯(lián)絡(luò)admin@php.cn

熱AI工具

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅(qū)動的應(yīng)用程序,用於創(chuàng)建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發(fā)環(huán)境

Dreamweaver CS6

Dreamweaver CS6

視覺化網(wǎng)頁開發(fā)工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

如何通過php中的索引訪問字符串中的字符 如何通過php中的索引訪問字符串中的字符 Jul 12, 2025 am 03:15 AM

在PHP中獲取字符串特定索引字符可用方括號或花括號,但推薦方括號;索引從0開始,超出範(fàn)圍訪問返回空值,不可賦值;處理多字節(jié)字符需用mb_substr。例如:$str="hello";echo$str[0];輸出h;而中文等字符需用mb_substr($str,1,1)獲取正確結(jié)果;實際應(yīng)用中循環(huán)訪問前應(yīng)檢查字符串長度,動態(tài)字符串需驗證有效性,多語言項目建議統(tǒng)一使用多字節(jié)安全函數(shù)。

發(fā)電機如何在PHP中工作? 發(fā)電機如何在PHP中工作? Jul 11, 2025 am 03:12 AM

AgeneratorinPHPisamemory-efficientwaytoiterateoverlargedatasetsbyyieldingvaluesoneatatimeinsteadofreturningthemallatonce.1.Generatorsusetheyieldkeywordtoproducevaluesondemand,reducingmemoryusage.2.Theyareusefulforhandlingbigloops,readinglargefiles,or

如何防止PHP中的會話劫持? 如何防止PHP中的會話劫持? Jul 11, 2025 am 03:15 AM

要防止PHP中的會話劫持,需採取以下措施:1.使用HTTPS加密傳輸並在php.ini中設(shè)置session.cookie_secure=1;2.設(shè)置安全Cookie屬性,包括httponly、secure和samesite;3.在用戶登錄或權(quán)限變更時調(diào)用session_regenerate_id(true)更換SessionID;4.限制Session生命週期,合理配置gc_maxlifetime並記錄用戶活動時間;5.禁止將SessionID暴露在URL中,設(shè)置session.use_only

php獲得字符串的第一個N字符 php獲得字符串的第一個N字符 Jul 11, 2025 am 03:17 AM

在PHP中取字符串前N個字符可用substr()或mb_substr(),具體步驟如下:1.使用substr($string,0,N)截取前N個字符,適用於ASCII字符且簡單高效;2.處理多字節(jié)字符(如中文)時應(yīng)使用mb_substr($string,0,N,'UTF-8'),並確保啟用mbstring擴展;3.若字符串含HTML或空白字符,應(yīng)先用strip_tags()去除標(biāo)籤、trim()清理空格,再截取以保證結(jié)果乾淨(jìng)。

PHP獲得字符串的最後N字符 PHP獲得字符串的最後N字符 Jul 11, 2025 am 03:17 AM

在PHP中獲取字符串最後N個字符主要有兩種方法:1.使用substr()函數(shù),通過負數(shù)起始位置截取,適用於單字節(jié)字符;2.使用mb_substr()函數(shù),支持多語言和UTF-8編碼,避免截斷非英文字符;3.可選地判斷字符串長度是否足夠以處理邊界情況;4.不推薦使用strrev() substr()的組合方式,因其對多字節(jié)字符不安全且效率低。

如何用urlencode在PHP中編碼字符串 如何用urlencode在PHP中編碼字符串 Jul 11, 2025 am 03:22 AM

urlencode()函數(shù)用於將字符串編碼為URL安全格式,其中非字母數(shù)字字符(除-、_和.外)會被替換為百分號後跟兩位十六進制數(shù)的形式。例如,空格轉(zhuǎn)為 號,感嘆號轉(zhuǎn)為!,而中文字符則轉(zhuǎn)換為其UTF-8編碼形式。使用時應(yīng)僅對參數(shù)值進行編碼,而非整個URL,以避免破壞URL結(jié)構(gòu)。對於URL的其他部分如路徑段,應(yīng)使用rawurlencode()函數(shù),其將空格轉(zhuǎn)為 。處理數(shù)組參數(shù)時可使用http_build_query()自動編碼,或手動對每個值調(diào)用urlencode()以確保安全傳輸數(shù)據(jù)。正

如何在PHP中設(shè)置和獲取會話變量? 如何在PHP中設(shè)置和獲取會話變量? Jul 12, 2025 am 03:10 AM

要設(shè)置和獲取PHP中的會話變量,首先必須始終在腳本頂部調(diào)用session_start()以啟動會話。 1.設(shè)置會話變量時,使用$_SESSION超全局?jǐn)?shù)組為特定鍵賦值,如$_SESSION['username']='john_doe';可存儲字符串、數(shù)字、數(shù)組甚至對象,但避免存儲過多數(shù)據(jù)以免影響性能。 2.獲取會話變量時,需先調(diào)用session_start(),然後通過鍵訪問$_SESSION數(shù)組,如echo$_SESSION['username'];建議使用isset()檢查變量是否存在以避免錯誤

如何防止PHP中的SQL注入 如何防止PHP中的SQL注入 Jul 12, 2025 am 03:02 AM

防止SQL注入在PHP中的關(guān)鍵方法包括:1.使用預(yù)處理語句(如PDO或MySQLi)分離SQL代碼和數(shù)據(jù);2.關(guān)閉模擬預(yù)處理模式確保真正預(yù)處理;3.對用戶輸入進行過濾和驗證,如使用is_numeric()和filter_var();4.避免直接拼接SQL字符串,改用參數(shù)綁定;5.生產(chǎn)環(huán)境關(guān)閉錯誤顯示並記錄錯誤日誌。這些措施從機制和細節(jié)上全面防範(fàn)SQL注入風(fēng)險。

See all articles