首頁 >後端開發 >php教程 >PHP 守護程式類

PHP 守護程式類

WBOY
WBOY原創
2016-07-25 09:06:45884瀏覽
複製程式碼
用 PHP 實作的 Daemon 類別。可以在伺服器上實作佇列或脫離 crontab 的排程任務。
使用的時候,繼承於這個類,並重寫 _doTask 方法,透過 main 初始化執行。
  1. class Daemon {
  2. const DLOG_TO_CONSOLE = 1;
  3. const DLOG_NOTICE = 2 const DLOG_ERROR = 8;
  4. const DLOG_CRITICAL = 16;
  5. const DAPC_PATH = '/tmp/daemon_apc_keys';
  6. /**
  7. /**
  8. * 使用者 ID
  9. *
  10. * @var int
  11. */
  12. public $groupID = 65533; // 沒人
  13. /**
  14. * 組 ID
  15. *
  16. * @var 整數
  17. */
  18. public $requireSetIdentity = false;
  19. /**
  20. * 設定身分失敗時終止守護程式?
  21. * @var bool
  22. * @since 1.0.3
  23. */
  24. public $pidFileLocation = '/ tmp /daemon.pid';
  25. /**
  26. * PID 檔案路徑
  27. *
  28. * @var string
  29. * @since 1.0.1
  30. */
  31. public $processLocation = '';
  32. /**
  33. * processLocation
  34. * 進程資訊記錄目錄
  35. *
  36. * @var string
  37. */
  38. public $ processHeartLocation = '';
  39. /**
  40. * processHeartLocation
  41. * 進程心跳包檔案
  42. *
  43. * @var string
  44. */
  45. public $homePath = '/';
  46. /**
  47. * 主路徑
  48. *
  49. * @var string
  50. * @since 1.0
  51. */
  52. protected $_pid = 0;
  53. /**
  54. * 目前進程 ID
  55. *
  56. * @var int
  57. * @since 1.0
  58. */
  59. protected $_isChildren = false;
  60. /**
  61. * 這個行程是子行程嗎
  62. *
  63. * @var boolean
  64. * @since 1.0
  65. */
  66. protected $_isRunning = false;
  67. /**
  68. * 守護程式正在執行
  69. *
  70. * @var boolean
  71. * @since 1.0
  72. */
  73. public function __construct() {
  74. error_reporting(0);
  75. set_time_limit(0);
  76. ob_implic); >
  77. register_shutdown_function(array(&$this, 'releaseDaemon'));
  78. }
  79. /**
  80. * 建構子
  81. *
  82. * @return void
  83. */
  84. public function main() {
  85. $this->_logMessage('正在啟動守護程序');
  86. if (!$this->_daemonize()) {
  87. $this->_logMessage('啟動啟動守護程序', self ::DLOG_ERROR);
  88. 回傳false;
  89. }
  90. $this->_logMessage('正在運作...');
  91. $this-> _isRunning = true;
  92. while ($this->_isRunning) {
  93. $this->_doTask();
  94. }
  95. 回傳true;
  96. }
  97. /**
  98. * 啟動進程
  99. *
  100. * @return bool
  101. */
  102. public function stop() {
  103. $this->_logMessage('守護停止程序');
  104. $this- >_isRunning = false;
  105. }
  106. /**
  107. * 停止進程
  108. *
  109. * @return void
  110. */
  111. protected function _doTask() {
  112. // 覆寫此方法
  113. }
  114. /**
  115. * 執行任務
  116. *
  117. * @return void
  118. */
  119. protected function _logMessage($msg, $level = self::DLOG_NOTICE) {
  120. // 覆寫此方法
  121. }
  122. /**
  123. * _logMessage
  124. * 記錄日誌
  125. *
  126. * @param string 訊息
  127. * @param integer 等級
  128. * @return void
  129. * @param integer 等級
  130. * @return void
  131. */
  132. private function _daemonize() {
  133. ob_end_flush();
  134. if ($this->_isDaemonRunning()) {
  135. // 守護程式已經執行。 return false;
  136. }
  137. if (!$this->_fork()) {
  138. // 無法分叉。 🎜> if (!$this->_setIdentity() && $this->requireSetIdentity) {
  139. // 必要的身份設定失敗。 !posix_setsid()) {
  140. $this->_logMessage('無法使當前進程成為會話領導者', self:: DLOG_ERROR);
  141. return false;
  142. }
  143. return false;
  144. }
  145. if (!$fp = fopen($this->pidFileLocation, 'w')) {
  146. $this-> ;_logMessage('無法寫入PID 檔案', self::DLOG_ERROR);
  147. return false ;
  148. } else {
  149. fputs($fp, $this->_pid);
  150. fclose ($fp);
  151. }
  152. // 寫入監控日誌
  153. $this->writeProcess();
  154. chdir($this->homePath);
  155. umask(0);
  156. 宣告(ticks = 1);
  157. pcntl_signal(SIGCHLD, array(&$this, 'sigHandler'));
  158. pcntl_signal(SIGTERM, array(&$this, 'sigHandler' cntl_signal(SIGTERM, array(&$this, 'sigHandler') cntl_signal(SIGTERM, array(&$this, 'sigHandler') cntl_signal;
  159. pcntl_signal(SIGUSR1, array(&$this, 'sigHandler'));
  160. pcntl_signal(SIGUSR2, array(&$this, 'sigHandler'));
  161. return true; }
  162. /**
  163. * Cheks 守護程式已在執行
  164. *
  165. * @return bool
  166. */
  167. 私有函數_isDaemonRunning() {
  168. $oldPid = file_get_contents($this->pidFileLocation);
  169. ($oldPid !== false && posix_kill(trim($oldPid),0))
  170. {
  171. $this->_logMessage('守護程式已經運行,PID: '.$oldPid, (self: :DLOG_TO_CONSOLE | self::DLOG_ERROR));
  172. 回傳true;
  173. }
  174. else
  175. {
  176. 回傳false;
  177. }
  178. }
  179. 回傳false;
  180. }
  181. }
  182. * 分岔進程
  183. *
  184. * @return bool
  185. */
  186. private function _fork() {
  187. $this->_logMessage('分叉...');
  188. $pid = pcntl_fork( );
  189. if ($pid == -1) {
  190. // 錯誤
  191. $this->_logMessage('無法分叉', self::DLOG_ERROR);
  192. return false;
  193. } elseif ($pid) {
  194. // 父程序
  195. $this->_logMessage('正在殺死父程序');
  196. exit();
  197. } else {
  198. // fork 的子程序
  199. $this->_isChildren = true;
  200. $this->_pid = posix_getpid();
  201. return true;
  202. }
  203. }
  204. /**
  205. * 設定守護程式的身份並回傳結果
  206. *
  207. * @return bool
  208. */
  209. private function _setIdentity() {
  210. if (!posix_setgid($this->groupID) || !posix_setuid($thisix_setuid($this->groupID) || !pos ->userID))
  211. {
  212. $this->_logMessage('無法設定身分', self::DLOG_WARNING);
  213. return false;
  214. }
  215. else
  216. return false;
  217. }
  218. else
  219. {
  220. return true;
  221. }
  222. }
  223. /**
  224. * 訊號處理程序
  225. *
  226. * @access public
  227. * @since 1.0
  228. * @return void
  229. */
  230. public function sigHandler($sigNo) {
  231. Noswitch ($sig )
  232. {
  233. case SIGTERM: // 關機
  234. $this->_logMessage('關機訊號');
  235. exit();
  236. break;
  237. case SIGCHLD: case SIGCHLD: // Halt
  238. $this->_logMessage('Halt signal');
  239. while (pcntl_waitpid(-1, $status, WNOHANG) > 0);
  240. break;
  241. case SIGUSR1: //用戶定義
  242. $this->_logMessage('用戶定義信號1');
  243. $this->_sigHandlerUser1();
  244. break;
  245. case SIGUSR2: // 用戶定義
  246. $this ->_logMessage('使用者定義訊號2');
  247. $this->_sigHandlerUser2();
  248. break;
  249. }
  250. }
  251. /**
  252. * Signals handler: USR1
  253. * 主要用於定時清理每個行程裡被快取的網域名稱dns解析記錄
  254. *
  255. * @return void
  256. */
  257. 受保護函數_sigHandlerUser1() {
  258. apc_clear_cache('user');
  259. }
  260. /* *
  261. * Signals handler: USR2
  262. * 用於寫入心跳包檔案
  263. *
  264. * @return void
  265. */
  266. protected function _s) >
  267. $this->_initProcessLocation();
  268. file_put_contents($this->processHeartLocation, time());
  269. return true;
  270. }
  271. }
  272. /**
  273. * 釋放守護程式 pid 檔案
  274. * 退出時呼叫此方法(類似析構函式)
  275. *
  276. * @return void
  277. */
  278. public function releaseDaemon() {
  279. if ($this->_isChildren && is_file($this->pidFileLocation)) {
  280. $this-> '釋放守護程式');
  281. unlink($this->pidFileLocation); } }
  282. /**
  283. * writeProcess
  284. * 將目前進程資訊寫入監控日誌,另外的腳本會掃描監控日誌的資料傳送訊號,如果沒有回應則重新啟動程式
  285. *
  286. * @return void
  287. */
  288. public function writeProcess() {
  289. // 初始化proc
  290. $this->_initProcessLocation();
  291. // 指定進程的目錄
  292. $processDir = $this->processLocation . '/' . $this ->_pid;
  293. $processCmdFile = $processDir . '/cmd';
  294. $processPwdFile = $processDir . '/pwd';
  295. // 所有進程所在的目錄
  296. if (> !is_dir($this->processLocation)) {
  297. mkdir($this->processLocation, 0777);
  298. chmod($processDir, 0777);
  299. }
  300. $pDirObject = dir($this->processLocation);
  301. while ($pDirObject && (($pid = $pDirObject->read()) !== false)) {
  302. if ($pid == '.' || $pid == '..' || intval($pid) != $pid) {
  303. continue;
  304. }
  305. $pDir = $ this->processLocation . '/' . $pid;
  306. $pCmdFile = $pDir . '/cmd';
  307. $pPwdFile = $pDir . '/pwd';
  308. $pHeartFile = $pDir . 'pDir . 'pDir . /heart';
  309. // 根據cmd檢查啟動相同參數的程序
  310. if (is_file($pCmdFile) && trim(file_get_contents($pCmdFile)) == $command) {
  311. unlink( $pCmdFile);
  312. unlink($pPwdFile);
  313. unlink($pHeartFile);
  314. // 刪除目錄有快取
  315. usleep(1000);
  316. }
  317. }
  318. // 新行程目錄
  319. if (!is_dir($processDir)) {
  320. mkdir($processDir, 0777);
  321. chmod($processDir, 0777);
  322. }
  323. // 寫入指令參數
  324. file_put_contents($processCmdFile, $command);
  325. file_put_contents($processCmdFile, $command);
  326. file_put_contents($processSERPFile, $. ]);
  327. // 寫檔案有快取
  328. usleep(1000);
  329. return true;
  330. }
  331. /**
  332. * _initProcessLocation
  333. * 初始化
  334. *
  335. * @return void
  336. 🎜> }
  337. /**//
  338. protected function _initProcessLocation() {
  339. $this->processLocation = ROOT_PATH . '/app/data/proc';
  340. $this->processHeartLocation = $this->processLocation. .' . $this->_pid . '/heart';
}
}


陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn