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

Rumah pembangunan bahagian belakang tutorial php 如何寫php守護(hù)進(jìn)程(Daemon)_php技巧

如何寫php守護(hù)進(jìn)程(Daemon)_php技巧

May 16, 2016 pm 08:01 PM
php daemon

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

<&#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; //最多運(yùn)行8個(gè)進(jìn)程 
  
  public function __construct($is_sington=false,$user='nobody',$output="/dev/null"){ 
  
      $this->is_sington=$is_sington; //是否單例運(yùn)行,單例運(yùn)行會(huì)在tmp目錄下建立一個(gè)唯一的PID 
      $this->user=$user;//設(shè)置運(yùn)行的用戶 默認(rèn)情況下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下面運(yùn)行 
    if (php_sapi_name() != "cli"){ 
      die("only run in command line mode\n"); 
    } 
  
    // 只能單例運(yù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){ //是父進(jìn)程,父進(jìn)程退出 
      exit(); 
    } 
  
    posix_setsid();//設(shè)置新會(huì)話組長,脫離終端 
  
    if (pcntl_fork() != 0){ //是第一子進(jìn)程,結(jié)束第一子進(jìn)程   
      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è)置運(yùn)行的用戶 
  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; 
      //子進(jìn)程結(jié)束信號 
      case SIGCHLD: 
        while(($pid=pcntl_waitpid(-1, $status, WNOHANG)) > 0){ 
          $this->workers_count --; 
        } 
      break; 
      //中斷進(jìn)程 
      case SIGTERM: 
      case SIGHUP: 
      case SIGQUIT: 
  
        $this->terminate = true; 
      break; 
      default: 
      return false; 
    } 
  
  } 
  /** 
  *開始開啟進(jìn)程 
  *$count 準(zhǔn)備開啟的進(jì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){ 
  
        // 這個(gè)符號表示恢復(fù)系統(tǒng)對信號的默認(rèn)處理 
        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); 
  
  } 
  
  //整個(gè)進(jìn)程退出 
  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); 
  } 
  
  // 添加工作實(shí)例,目前只支持單個(gè)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("你必須添加運(yùn)行的函數(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個(gè)子進(jìn)程工作 
work(); 
  
  
  
  
//調(diào)用方法2 
$daemon=new DaemonCommand(true); 
$daemon->daemonize(); 
$daemon->addJobs(array('function'=>'work','argv'=>'','runtime'=>1000));//function 要運(yùn)行的函數(shù),argv運(yùn)行函數(shù)的參數(shù),runtime運(yùn)行的次數(shù) 
$daemon->start(2);//開啟2個(gè)子進(jìn)程工作 
  
//具體功能的實(shí)現(xiàn) 
function work(){ 
   echo "測試1"; 
} 
&#63;> 

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

Kenyataan Laman Web ini
Kandungan artikel ini disumbangkan secara sukarela oleh netizen, dan hak cipta adalah milik pengarang asal. Laman web ini tidak memikul tanggungjawab undang-undang yang sepadan. Jika anda menemui sebarang kandungan yang disyaki plagiarisme atau pelanggaran, sila hubungi admin@php.cn

Alat AI Hot

Undress AI Tool

Undress AI Tool

Gambar buka pakaian secara percuma

Undresser.AI Undress

Undresser.AI Undress

Apl berkuasa AI untuk mencipta foto bogel yang realistik

AI Clothes Remover

AI Clothes Remover

Alat AI dalam talian untuk mengeluarkan pakaian daripada foto.

Clothoff.io

Clothoff.io

Penyingkiran pakaian AI

Video Face Swap

Video Face Swap

Tukar muka dalam mana-mana video dengan mudah menggunakan alat tukar muka AI percuma kami!

Alat panas

Notepad++7.3.1

Notepad++7.3.1

Editor kod yang mudah digunakan dan percuma

SublimeText3 versi Cina

SublimeText3 versi Cina

Versi Cina, sangat mudah digunakan

Hantar Studio 13.0.1

Hantar Studio 13.0.1

Persekitaran pembangunan bersepadu PHP yang berkuasa

Dreamweaver CS6

Dreamweaver CS6

Alat pembangunan web visual

SublimeText3 versi Mac

SublimeText3 versi Mac

Perisian penyuntingan kod peringkat Tuhan (SublimeText3)

Bagaimana untuk mendapatkan ID sesi semasa dalam PHP? Bagaimana untuk mendapatkan ID sesi semasa dalam PHP? Jul 13, 2025 am 03:02 AM

Kaedah untuk mendapatkan ID sesi semasa dalam PHP adalah menggunakan fungsi session_id (), tetapi anda mesti menghubungi session_start () untuk berjaya mendapatkannya. 1. Panggil session_start () untuk memulakan sesi; 2. Gunakan session_id () untuk membaca ID Sesi dan mengeluarkan rentetan yang serupa dengan ABC123DEF456GHI789; 3 Jika pulangan kosong, periksa sama ada session_start () hilang, sama ada pengguna mengakses untuk kali pertama, atau sama ada sesi dimusnahkan; 4. ID Sesi boleh digunakan untuk pembalakan, pengesahan keselamatan dan komunikasi silang, tetapi keselamatan perlu diberi perhatian. Pastikan sesi itu diaktifkan dengan betul dan ID boleh diperolehi dengan jayanya.

Php mendapatkan substring dari rentetan Php mendapatkan substring dari rentetan Jul 13, 2025 am 02:59 AM

Untuk mengekstrak substrings dari rentetan php, anda boleh menggunakan fungsi substr (), iaitu substra sintaks (string $ string, int $ start ,? int $ panjang = null), dan jika panjang tidak ditentukan, ia akan dipintas hingga akhir; Apabila memproses aksara berbilang bit seperti Cina, anda harus menggunakan fungsi MB_SUBSTR () untuk mengelakkan kod yang dihiasi; Jika anda perlu memintas rentetan mengikut pemisah tertentu, anda boleh menggunakan Eksploitasi () atau menggabungkan StrPOS () dan Substr () untuk melaksanakannya, seperti mengekstrak sambungan nama fail atau nama domain.

Bagaimana anda melakukan ujian unit untuk kod PHP? Bagaimana anda melakukan ujian unit untuk kod PHP? Jul 13, 2025 am 02:54 AM

UnittestinginphpinvolvesveryingindividualcodeUnitsLikeFunctionsormethodstocatchbugsearlyandensurerurereliableFactoring.1) setupphpunitviacomposer, createatestdirectory, danconfigureautoloadandphpunit.xml.2soSteSteSteShpunit.xml.2)

Cara memisahkan rentetan ke dalam array dalam php Cara memisahkan rentetan ke dalam array dalam php Jul 13, 2025 am 02:59 AM

Dalam PHP, kaedah yang paling biasa adalah untuk memecah rentetan ke dalam array menggunakan fungsi eksploit (). Fungsi ini membahagikan rentetan ke dalam pelbagai bahagian melalui pembatas yang ditentukan dan mengembalikan array. Sintaks adalah eksploit (pemisah, rentetan, had), di mana pemisah adalah pemisah, rentetan adalah rentetan asal, dan had adalah parameter pilihan untuk mengawal bilangan maksimum segmen. Contohnya $ str = "epal, pisang, oren"; $ arr = meletup (",", $ str); Hasilnya ialah ["Apple", "Bana

Jenis Data JavaScript: Rujukan primitif vs Jenis Data JavaScript: Rujukan primitif vs Jul 13, 2025 am 02:43 AM

Jenis data JavaScript dibahagikan kepada jenis primitif dan jenis rujukan. Jenis primitif termasuk rentetan, nombor, boolean, null, undefined, dan simbol. Nilai -nilai tidak berubah dan salinan disalin apabila memberikan nilai, jadi mereka tidak mempengaruhi satu sama lain; Jenis rujukan seperti objek, tatasusunan dan fungsi menyimpan alamat memori, dan pembolehubah menunjuk objek yang sama akan mempengaruhi satu sama lain. Typeof dan Instanceof boleh digunakan untuk menentukan jenis, tetapi memberi perhatian kepada isu -isu sejarah TypeOfNull. Memahami kedua -dua jenis perbezaan ini dapat membantu menulis kod yang lebih stabil dan boleh dipercayai.

Menggunakan std :: chrono di c Menggunakan std :: chrono di c Jul 15, 2025 am 01:30 AM

STD :: Chrono digunakan dalam C untuk memproses masa, termasuk mendapatkan masa semasa, mengukur masa pelaksanaan, titik masa operasi dan tempoh, dan masa analisis pemformatan. 1. Gunakan std :: chrono :: system_clock :: sekarang () untuk mendapatkan masa semasa, yang boleh ditukar menjadi rentetan yang boleh dibaca, tetapi jam sistem mungkin tidak membosankan; 2. Gunakan std :: chrono :: steady_clock untuk mengukur masa pelaksanaan untuk memastikan monoton, dan mengubahnya menjadi milisaat, saat dan unit lain melalui duration_cast; 3. Titik masa (time_point) dan tempoh (tempoh) boleh saling beroperasi, tetapi perhatian harus dibayar kepada keserasian unit dan zaman jam (Epoch)

Bagaimanakah PHP mengendalikan pembolehubah persekitaran? Bagaimanakah PHP mengendalikan pembolehubah persekitaran? Jul 14, 2025 am 03:01 AM

ToAccessenVironmentVariablesInphp, useGetenv () orthe $ _envsuperglobal.1.getenv ('var_name') retrievesaspecificvariable.2. $ _ En V ['var_name'] AccessSvariablesifvariables_orderinphp.iniincludes "e" .setVariablesviacliwithvar = valuePhpscript.php, inapach

Apa yang lewat mengikat statik dalam PHP? Apa yang lewat mengikat statik dalam PHP? Jul 13, 2025 am 02:36 AM

Latihan terbaharuiCBindingInphpallowsStatic :: torefertotheclassinitiallycalledatruntimeinheritancescenarios.beforephp5.3, self :: SwasRerenceedTheClasswheretherethodwasdefined, causeDildChin

See all articles