侯体宗的博客
  • 首页
  • Hyperf版
  • beego仿版
  • 人生(杂谈)
  • 技术
  • 关于我
  • 更多分类
    • 文件下载
    • 文字修仙
    • 中国象棋ai
    • 群聊
    • 九宫格抽奖
    • 拼图
    • 消消乐
    • 相册

PHP高级编程实例:编写守护进程

php  /  管理员 发布于 7年前   151

1.什么是守护进程

守护进程是脱离于终端并且在后台运行的进程。守护进程脱离于终端是为了避免进程在执行过程中的信息在任何终端上显示并且进程也不会被任何终端所产生的终端信息所打断。

例如 apache, nginx, mysql 都是守护进程

2.为什么开发守护进程

很多程序以服务形式存在,他没有终端或UI交互,它可能采用其他方式与其他程序交互,如TCP/UDP Socket, UNIX Socket, fifo。程序一旦启动便进入后台,直到满足条件他便开始处理任务。

3.何时采用守护进程开发应用程序

以我当前的需求为例,我需要运行一个程序,然后监听某端口,持续接受服务端发起的数据,然后对数据分析处理,再将结果写入到数据库中; 我采用ZeroMQ实现数据收发。

如果我不采用守护进程方式开发该程序,程序一旦运行就会占用当前终端窗框,还有受到当前终端键盘输入影响,有可能程序误退出。

4.守护进程的安全问题

我们希望程序在非超级用户运行,这样一旦由于程序出现漏洞被骇客控制,攻击者只能继承运行权限,而无法获得超级用户权限。

我们希望程序只能运行一个实例,不运行同事开启两个以上的程序,因为会出现端口冲突等等问题。

5.怎样开发守护进程

例 1. 守护进程例示

logger = $logger; #} #protected $logger; protected static $dbh; public function __construct() { } public function run(){  $dbhost = '192.168.2.1';  // 数据库服务器  $dbport = 3306;   $dbuser = 'www';  // 数据库用户名 $dbpass = 'qwer123';    // 数据库密码  $dbname = 'example';  // 数据库名  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文件来判断,当前进程状态,如果进程ID文件存在表示程序在运行中,通过代码file_exists($this->pidfile)实现,但而后进程被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文件,然后调用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);  } }

您可能感兴趣的文章:

  • php守护进程 加linux命令nohup实现任务每秒执行一次
  • shell脚本作为保证PHP脚本不挂掉的守护进程实例分享
  • 如何写php守护进程(Daemon)
  • PHP将进程作为守护进程的方法
  • PHP扩展程序实现守护进程
  • PHP实现多进程并行操作的详解(可做守护进程)
  • PHP守护进程的两种常见实现方式详解
  • PHP程序员玩转Linux系列 使用supervisor实现守护进程
  • PHP程序级守护进程的实现与优化的使用概述
  • php脚本守护进程原理与实现方法详解
  • PHP守护进程化在C和PHP环境下的实现
  • php实现简单的守护进程创建、开启与关闭操作


  • 上一条:
    Yii 快速,安全,专业的PHP框架
    下一条:
    php输入流php://input使用浅析
  • 昵称:

    邮箱:

    0条评论 (评论内容有缓存机制,请悉知!)
    最新最热
    • 分类目录
    • 人生(杂谈)
    • 技术
    • linux
    • Java
    • php
    • 框架(架构)
    • 前端
    • ThinkPHP
    • 数据库
    • 微信(小程序)
    • Laravel
    • Redis
    • Docker
    • Go
    • swoole
    • Windows
    • Python
    • 苹果(mac/ios)
    • 相关文章
    • Laravel从Accel获得5700万美元A轮融资(0个评论)
    • PHP 8.4 Alpha 1现已发布!(0个评论)
    • 用Time Warden监控PHP中的代码处理时间(0个评论)
    • 在PHP中使用array_pop + yield实现读取超大型目录功能示例(0个评论)
    • Property Hooks RFC在PHP 8.4中越来越接近现实(0个评论)
    • 近期文章
    • 智能合约Solidity学习CryptoZombie第四课:僵尸作战系统(0个评论)
    • 智能合约Solidity学习CryptoZombie第三课:组建僵尸军队(高级Solidity理论)(0个评论)
    • 智能合约Solidity学习CryptoZombie第二课:让你的僵尸猎食(0个评论)
    • 智能合约Solidity学习CryptoZombie第一课:生成一只你的僵尸(0个评论)
    • 在go中实现一个常用的先进先出的缓存淘汰算法示例代码(0个评论)
    • 在go+gin中使用"github.com/skip2/go-qrcode"实现url转二维码功能(0个评论)
    • 在go语言中使用api.geonames.org接口实现根据国际邮政编码获取地址信息功能(1个评论)
    • 在go语言中使用github.com/signintech/gopdf实现生成pdf分页文件功能(0个评论)
    • gmail发邮件报错:534 5.7.9 Application-specific password required...解决方案(0个评论)
    • 欧盟关于强迫劳动的规定的官方举报渠道及官方举报网站(0个评论)
    • 近期评论
    • 122 在

      学历:一种延缓就业设计,生活需求下的权衡之选中评论 工作几年后,报名考研了,到现在还没认真学习备考,迷茫中。作为一名北漂互联网打工人..
    • 123 在

      Clash for Windows作者删库跑路了,github已404中评论 按理说只要你在国内,所有的流量进出都在监控范围内,不管你怎么隐藏也没用,想搞你分..
    • 原梓番博客 在

      在Laravel框架中使用模型Model分表最简单的方法中评论 好久好久都没看友情链接申请了,今天刚看,已经添加。..
    • 博主 在

      佛跳墙vpn软件不会用?上不了网?佛跳墙vpn常见问题以及解决办法中评论 @1111老铁这个不行了,可以看看近期评论的其他文章..
    • 1111 在

      佛跳墙vpn软件不会用?上不了网?佛跳墙vpn常见问题以及解决办法中评论 网站不能打开,博主百忙中能否发个APP下载链接,佛跳墙或极光..
    • 2016-10
    • 2016-11
    • 2017-06
    • 2017-07
    • 2017-08
    • 2017-09
    • 2017-11
    • 2017-12
    • 2018-01
    • 2018-02
    • 2018-03
    • 2020-03
    • 2020-04
    • 2020-05
    • 2020-06
    • 2020-07
    • 2020-09
    • 2021-02
    • 2021-03
    • 2021-04
    • 2021-05
    • 2021-06
    • 2021-07
    • 2021-08
    • 2021-09
    • 2021-10
    • 2021-11
    • 2021-12
    • 2022-01
    • 2022-02
    • 2022-05
    • 2022-06
    • 2022-07
    • 2022-08
    • 2022-09
    • 2022-10
    • 2022-11
    • 2022-12
    • 2023-01
    • 2023-02
    • 2023-03
    • 2023-04
    • 2023-05
    • 2023-06
    • 2023-07
    • 2023-08
    • 2023-09
    • 2023-10
    • 2023-11
    • 2023-12
    • 2024-01
    • 2024-02
    • 2024-03
    • 2024-04
    • 2024-05
    • 2024-06
    • 2024-07
    • 2024-09
    Top

    Copyright·© 2019 侯体宗版权所有· 粤ICP备20027696号 PHP交流群

    侯体宗的博客