欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

PHP高級編程實(shí)例:編寫守護(hù)進(jìn)程

 更新時間:2014年09月02日 09:43:23   投稿:junjie  
這篇文章主要介紹了PHP高級編程實(shí)例:編寫守護(hù)進(jìn)程,守護(hù)進(jìn)程是脫離于終端并且在后臺運(yùn)行的進(jìn)程,本文講解使用PHP編寫守護(hù)進(jìn)程,并給出了代碼實(shí)例,需要的朋友可以參考下

1.什么是守護(hù)進(jìn)程

守護(hù)進(jìn)程是脫離于終端并且在后臺運(yùn)行的進(jìn)程。守護(hù)進(jìn)程脫離于終端是為了避免進(jìn)程在執(zhí)行過程中的信息在任何終端上顯示并且進(jìn)程也不會被任何終端所產(chǎn)生的終端信息所打斷。

例如 apache, nginx, mysql 都是守護(hù)進(jìn)程

2.為什么開發(fā)守護(hù)進(jìn)程

很多程序以服務(wù)形式存在,他沒有終端或UI交互,它可能采用其他方式與其他程序交互,如TCP/UDP Socket, UNIX Socket, fifo。程序一旦啟動便進(jìn)入后臺,直到滿足條件他便開始處理任務(wù)。

3.何時采用守護(hù)進(jìn)程開發(fā)應(yīng)用程序

以我當(dāng)前的需求為例,我需要運(yùn)行一個程序,然后監(jiān)聽某端口,持續(xù)接受服務(wù)端發(fā)起的數(shù)據(jù),然后對數(shù)據(jù)分析處理,再將結(jié)果寫入到數(shù)據(jù)庫中; 我采用ZeroMQ實(shí)現(xiàn)數(shù)據(jù)收發(fā)。

如果我不采用守護(hù)進(jìn)程方式開發(fā)該程序,程序一旦運(yùn)行就會占用當(dāng)前終端窗框,還有受到當(dāng)前終端鍵盤輸入影響,有可能程序誤退出。

4.守護(hù)進(jìn)程的安全問題

我們希望程序在非超級用戶運(yùn)行,這樣一旦由于程序出現(xiàn)漏洞被駭客控制,攻擊者只能繼承運(yùn)行權(quán)限,而無法獲得超級用戶權(quán)限。

我們希望程序只能運(yùn)行一個實(shí)例,不運(yùn)行同事開啟兩個以上的程序,因?yàn)闀霈F(xiàn)端口沖突等等問題。

5.怎樣開發(fā)守護(hù)進(jìn)程

例 1. 守護(hù)進(jìn)程例示

<?php
class ExampleWorker extends Worker {

 #public function __construct(Logging $logger) {
 # $this->logger = $logger;
 #}

 #protected $logger;
 protected static $dbh;
 public function __construct() {

 }
 public function run(){
  $dbhost = '192.168.2.1';  // 數(shù)據(jù)庫服務(wù)器
  $dbport = 3306;
   $dbuser = 'www';  // 數(shù)據(jù)庫用戶名
 $dbpass = 'qwer123';    // 數(shù)據(jù)庫密碼
  $dbname = 'example';  // 數(shù)據(jù)庫名

  self::$dbh = new PDO("mysql:host=$dbhost;port=$dbport;dbname=$dbname", $dbuser, $dbpass, array(
   /* PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES \'UTF8\'', */
   PDO::MYSQL_ATTR_COMPRESS => true,
   PDO::ATTR_PERSISTENT => true
   )
  );

 }
 protected function getInstance(){
 return self::$dbh;
  }

}

/* the collectable class implements machinery for Pool::collect */
class Fee extends Stackable {
 public function __construct($msg) {
  $trades = explode(",", $msg);
  $this->data = $trades;
  print_r($trades);
 }

 public function run() {
  #$this->worker->logger->log("%s executing in Thread #%lu", __CLASS__, $this->worker->getThreadId() );

  try {
   $dbh = $this->worker->getInstance();
   
   $insert = "INSERT INTO fee(ticket, login, volume, `status`) VALUES(:ticket, :login, :volume,'N')";
   $sth = $dbh->prepare($insert);
   $sth->bindValue(':ticket', $this->data[0]);
   $sth->bindValue(':login', $this->data[1]);
   $sth->bindValue(':volume', $this->data[2]);
   $sth->execute();
   $sth = null;
   
   /* ...... */
   
   $update = "UPDATE fee SET `status` = 'Y' WHERE ticket = :ticket and `status` = 'N'";
   $sth = $dbh->prepare($update);
   $sth->bindValue(':ticket', $this->data[0]);
   $sth->execute();
   //echo $sth->queryString;
   //$dbh = null;
  }
  catch(PDOException $e) {
   $error = sprintf("%s,%s\n", $mobile, $id );
   file_put_contents("mobile_error.log", $error, FILE_APPEND);
  }
 }
}

class Example {
 /* config */
 const LISTEN = "tcp://192.168.2.15:5555";
 const MAXCONN = 100;
 const pidfile = __CLASS__;
 const uid = 80;
 const gid = 80;
 
 protected $pool = NULL;
 protected $zmq = NULL;
 public function __construct() {
  $this->pidfile = '/var/run/'.self::pidfile.'.pid';
 }
 private function daemon(){
  if (file_exists($this->pidfile)) {
   echo "The file $this->pidfile exists.\n";
   exit();
  }
  
  $pid = pcntl_fork();
  if ($pid == -1) {
    die('could not fork');
  } else if ($pid) {
    // we are the parent
    //pcntl_wait($status); //Protect against Zombie children
   exit($pid);
  } else {
   // we are the child
   file_put_contents($this->pidfile, getmypid());
   posix_setuid(self::uid);
   posix_setgid(self::gid);
   return(getmypid());
  }
 }
 private function start(){
  $pid = $this->daemon();
  $this->pool = new Pool(self::MAXCONN, \ExampleWorker::class, []);
  $this->zmq = new ZMQSocket(new ZMQContext(), ZMQ::SOCKET_REP);
  $this->zmq->bind(self::LISTEN);
  
  /* Loop receiving and echoing back */
  while ($message = $this->zmq->recv()) {
   //print_r($message);
   //if($trades){
     $this->pool->submit(new Fee($message));
     $this->zmq->send('TRUE'); 
   //}else{
   // $this->zmq->send('FALSE'); 
   //}
  }
  $pool->shutdown(); 
 }
 private function stop(){

  if (file_exists($this->pidfile)) {
   $pid = file_get_contents($this->pidfile);
   posix_kill($pid, 9); 
   unlink($this->pidfile);
  }
 }
 private function help($proc){
  printf("%s start | stop | help \n", $proc);
 }
 public function main($argv){
  if(count($argv) < 2){
   printf("please input help parameter\n");
   exit();
  }
  if($argv[1] === 'stop'){
   $this->stop();
  }else if($argv[1] === 'start'){
   $this->start();
  }else{
   $this->help($argv[0]);
  }
 }
}

$cgse = new Example();
$cgse->main($argv);

5.1. 程序啟動

下面是程序啟動后進(jìn)入后臺的代碼

通過進(jìn)程ID文件來判斷,當(dāng)前進(jìn)程狀態(tài),如果進(jìn)程ID文件存在表示程序在運(yùn)行中,通過代碼file_exists($this->pidfile)實(shí)現(xiàn),但而后進(jìn)程被kill需要手工刪除該文件才能運(yùn)行

private function daemon(){
  if (file_exists($this->pidfile)) {
   echo "The file $this->pidfile exists.\n";
   exit();
  }
  
  $pid = pcntl_fork();
  if ($pid == -1) {
    die('could not fork');
  } else if ($pid) {
   // we are the parent
   //pcntl_wait($status); //Protect against Zombie children
   exit($pid);
  } else {
   // we are the child
   file_put_contents($this->pidfile, getmypid());
   posix_setuid(self::uid);
   posix_setgid(self::gid);
   return(getmypid());
  }
 }

程序啟動后,父進(jìn)程會推出,子進(jìn)程會在后臺運(yùn)行,子進(jìn)程權(quán)限從root切換到指定用戶,同時將pid寫入進(jìn)程ID文件。

5.2. 程序停止

程序停止,只需讀取pid文件,然后調(diào)用posix_kill($pid, 9); 最后將該文件刪除。

private function stop(){

  if (file_exists($this->pidfile)) {
   $pid = file_get_contents($this->pidfile);
   posix_kill($pid, 9); 
   unlink($this->pidfile);
  }
 }

相關(guān)文章

最新評論