国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 開發(fā) > PHP > 正文

PHP高級編程實例:編寫守護進程

2024-05-04 23:25:30
字體:
供稿:網(wǎng)友
這篇文章主要介紹了PHP高級編程實例:編寫守護進程,守護進程是脫離于終端并且在后臺運行的進程,本文講解使用PHP編寫守護進程,并給出了代碼實例,需要的朋友可以參考下
 
 

1.什么是守護進程

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

例如 apache, nginx, mysql 都是守護進程

2.為什么開發(fā)守護進程

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

3.何時采用守護進程開發(fā)應用程序

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

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

4.守護進程的安全問題

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

我們希望程序只能運行一個實例,不運行同事開啟兩個以上的程序,因為會出現(xiàn)端口沖突等等問題。

5.怎樣開發(fā)守護進程

例 1. 守護進程例示

<?phpclass 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ù)庫服務器  $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. 程序啟動

下面是程序啟動后進入后臺的代碼

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

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());  } }

程序啟動后,父進程會推出,子進程會在后臺運行,子進程權限從root切換到指定用戶,同時將pid寫入進程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);  } }
 

發(fā)表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發(fā)表
主站蜘蛛池模板: 铜陵市| 霸州市| 建湖县| 赞皇县| 光泽县| 安福县| 台前县| 高尔夫| 丘北县| 贡觉县| 巫山县| 武强县| 永福县| 武清区| 奇台县| 清苑县| 兴海县| 江门市| 五大连池市| 龙岩市| 甘谷县| 连南| 沾化县| 曲阳县| 天长市| 马龙县| 和林格尔县| 浦县| 仁怀市| 股票| 游戏| 雷波县| 勐海县| 永安市| 容城县| 北海市| 余庆县| 资中县| 台北县| 家居| 朔州市|