PHPデーモンクラス

WBOY
リリース: 2016-07-25 09:06:45
オリジナル
866 人が閲覧しました
PHPで実装されたDaemonクラス。サーバー上の crontab からキューやスケジュールされたタスクを実装できます。
使用する場合は、このクラスを継承し、_doTaskメソッドをオーバーライドし、main経由で初期化して実行します。
  1. クラスデーモン{
  2. const DLOG_TO_CONSOLE = 1;
  3. const DLOG_NOTICE = 2;
  4. const DLOG_WARNING = 4;
  5. const DLOG_ERROR = 8;
  6. const DLOG_CRITICAL = 16;
  7. const DAPC_PATH = ' /tmp/daemon_apc_keys';
  8. /**
  9. * ユーザーID
  10. *
  11. * @var int
  12. */
  13. public $userID = 65534; // 誰も
  14. /**
  15. * グループID
  16. *
  17. * @var integer
  18. */
  19. public $groupID = 65533; // 誰も
  20. /**
  21. * ID 設定失敗時にデーモンを終了します ?
  22. *
  23. * @var bool
  24. * @since 1.0.3
  25. */
  26. public $requireSetIdentity = false;
  27. /**
  28. * PID ファイルへのパス
  29. *
  30. * @var string
  31. * @since 1.0.1
  32. */
  33. public $pidFileLocation = '/tmp/daemon.pid';
  34. /**
  35. * processLocation
  36. * プロセス情報記録ディレクトリ
  37. *
  38. * @var string
  39. */
  40. public $processLocation = '';
  41. /**
  42. * processHeartLocation
  43. * プロセスハートビートパケットファイル
  44. *
  45. * @var string
  46. */
  47. public $processHeartLocation = '';
  48. /**
  49. * ホームパス
  50. *
  51. * @var string
  52. * @since 1.0
  53. */
  54. public $homePath = '/';
  55. /**
  56. * 現在のプロセス ID
  57. *
  58. * @var int
  59. * @since 1.0
  60. */
  61. protected $_pid = 0;
  62. /**
  63. * このプロセスは子供ですか
  64. *
  65. * @var boolean
  66. * @since 1.0
  67. */
  68. protected $_isChildren = false;
  69. /**
  70. * デーモンは実行されていますか
  71. *
  72. * @var boolean
  73. * @since 1.0
  74. */
  75. protected $_isRunning = false;
  76. /**
  77. * コンストラクター
  78. *
  79. * @return void
  80. */
  81. public function __construct() {
  82. error_reporting(0);
  83. set_time_limit(0);
  84. ob_implicit_flush();
  85. register_shutdown_function(array(&$this, 'releaseDaemon')) ;
  86. }
  87. /**
  88. * プロセス開始
  89. *
  90. * @return bool
  91. */
  92. public function main() {
  93. $this->_logMessage('デーモンの起動');
  94. if (!$this->_daemonize()) {
  95. $this->_logMessage('デーモンを起動できませんでした', self::DLOG_ERROR);
  96. return false;
  97. }
  98. $this->_logMessage('実行中...');
  99. $this- >_isRunning = true;
  100. while ($this->_isRunning) {
  101. $this->_doTask();
  102. }
  103. return true;
  104. }
  105. /**
  106. * プロセスを停止します
  107. *
  108. * @return void
  109. */
  110. public function stop() {
  111. $this->_logMessage('デーモンの停止');
  112. $this->_isRunning = false;
  113. }
  114. /**
  115. * タスクを実行します
  116. *
  117. * @return void
  118. */
  119. 保護された関数 _doTask() {
  120. // このメソッドをオーバーライドします
  121. }
  122. /**
  123. * _logMessage
  124. * ログを記録します
  125. *
  126. * @param 文字列メッセージ
  127. * @param 整数レベル
  128. * @return void
  129. */
  130. protected function _logMessage($msg, $level = self::DLOG_NOTICE) {
  131. // このメソッドをオーバーライドします
  132. }
  133. /**
  134. * デーモン化
  135. *
  136. * ほとんどのデーモンが持ついくつかのルールまたは特性:
  137. * 1) デーモンが既に実行されているかどうかを確認する
  138. * 2) 子プロセスをフォークする
  139. * 3) ID を設定する
  140. * 4) 現在のプロセスをセッション レイヤーにする
  141. * 5) プロセスIDをファイルに書き込む
  142. * 6) ホームパスを変更する
  143. * 7) umask(0)
  144. *
  145. * @access private
  146. * @since 1.0
  147. * @return void
  148. */
  149. プライベート関数 _daemonize() {
  150. ob_end_flush();
  151. if ($this->_isDaemonRunning()) {
  152. // デーモンはすでに実行されています。終了します
  153. return false;
  154. }
  155. if (!$this->_fork()) {
  156. // フォークできませんでした。 Exiting.
  157. return false;
  158. }
  159. if (!$this->setIdentity() && $this->gt;requireSetIdentity) {
  160. // 必要な ID セットが失敗しました。終了中
  161. return false;
  162. }
  163. if (!posix_setsid()) {
  164. $this->_logMessage('現在のプロセスをセッション リーダーにできませんでした', self::DLOG_ERROR);
  165. return false;
  166. }
  167. if (!$fp = fopen($this->pidFileLocation, 'w')) {
  168. $this->_logMessage('PID ファイルに書き込めませんでした', self::DLOG_ERROR);
  169. return false;
  170. } else {
  171. fputs($fp, $this->_pid);
  172. fclose($fp);
  173. }
  174. // 書入监控日志
  175. $this->writeProcess();
  176. chdir($this->homePath);
  177. umask(0);
  178. declare(ticks = 1);
  179. pcntl_signal(SIGCHLD 、array(&$this, 'sigHandler'));
  180. pcntl_signal(SIGTERM, array(&$this, 'sigHandler'));
  181. pcntl_signal(SIGUSR1, array(&$this, 'sigHandler'));
  182. pcntl_signal( SIGUSR2, array(&$this, 'sigHandler'));
  183. return true;
  184. }
  185. /**
  186. * Cheks はデーモンがすでに実行されています
  187. *
  188. * @return bool
  189. */
  190. プライベート関数 _isDaemonRunning() {
  191. $oldPid = file_get_contents($this-> pidFileLocation);
  192. if ($oldPid !== false && posix_kill(trim($oldPid),0))
  193. {
  194. $this->_logMessage('デーモンはすでに PID で実行中です: '.$oldPid, (self: :DLOG_TO_CONSOLE self::DLOG_ERROR));
  195. return true;
  196. }
  197. else
  198. {
  199. return false;
  200. }
  201. }
  202. /**
  203. * フォークプロセス
  204. *
  205. * @return bool
  206. */
  207. プライベート関数 _fork() {
  208. $this ->_logMessage('フォーク中...');
  209. $pid = pcntl_fork();
  210. if ($pid == -1) {
  211. // 出错
  212. $this->_logMessage('フォークできませんでした', self::DLOG_ERROR);
  213. return false;
  214. } elseif ($pid) {
  215. // 父进程
  216. $this->_logMessage('親殺し');
  217. exit();
  218. } else {
  219. // フォーク的な子手続き
  220. $this->_isChildren = true;
  221. $this->_pid = posix_getpid();
  222. return true;
  223. }
  224. }
  225. /**
  226. * デーモンの ID を設定し、結果を返します
  227. *
  228. * @return bool
  229. */
  230. private function _setIdentity() {
  231. if (!posix_setgid($this->groupID) || !posix_setuid($this->userID))
  232. {
  233. $this->_logMessage('ID を設定できませんでした', self::DLOG_WARNING);
  234. return false;
  235. }
  236. else
  237. {
  238. return true;
  239. }
  240. }
  241. /**
  242. * シグナルハンドラー
  243. *
  244. * @access public
  245. * @since 1.0
  246. * @return void
  247. */
  248. public function sigHandler($sigNo) {
  249. switch ($sigNo)
  250. {
  251. case SIGTERM: // Shutdown
  252. $this->_logMessage('Shutdown signal' );
  253. exit();
  254. Break;
  255. case SIGCHLD: // Halt
  256. $this->_logMessage('Halt signal');
  257. while (pcntl_waitpid(-1, $status, WNOHANG) > 0);
  258. Break;
  259. case SIGUSR1: // ユーザー定義
  260. $this->_logMessage('ユーザー定義シグナル 1');
  261. $this->_sigHandlerUser1();
  262. Break;
  263. case SIGUSR2: // ユーザー-定義済み
  264. $this->_logMessage('ユーザー定義シグナル 2');
  265. $this->_sigHandlerUser2();
  266. Break;
  267. }
  268. }
  269. /**
  270. * シグナルハンドラー: USR1
  271. * 主に、各プロセスでキャッシュされたドメイン名の DNS 解決レコードを定期的にクリーンアップするために使用されます
  272. *
  273. * @return void
  274. */
  275. protected function _sigHandlerUser1( ) {
  276. apc_clear_cache('user');
  277. }
  278. /**
  279. * シグナルハンドラー: USR2
  280. * ハートビートパケットファイルの書き込みに使用されます
  281. *
  282. * @return void
  283. */
  284. protected function _sigHandlerUser2() {
  285. $this->_initProcessLocation();
  286. file_put_contents($this->processHeartLocation 、 time());
  287. return true;
  288. }
  289. /**
  290. * デーモンの PID ファイルを解放します
  291. * このメソッドは終了時に呼び出されます (デストラクターのような)
  292. *
  293. * @return void
  294. */
  295. public function releaseDaemon() {
  296. if ($this->_isChildren && is_file($this->pidFileLocation) ) {
  297. $this->_logMessage('デーモンの解放');
  298. unlink($this->pidFileLocation);
  299. }
  300. }
  301. /**
  302. * writeProcess
  303. * 現在のプロセス情報を監視ログに書き込みます。別のスクリプトが監視ログのデータをスキャンし、応答がない場合はプロセスを再起動します
  304. *
  305. * @return void
  306. */
  307. public function writeProcess() {
  308. // proc を初期化します
  309. $this->_initProcessLocation();
  310. $command = trim(implode(' ', $_SERVER['argv ']));
  311. // プロセスのディレクトリを指定します
  312. $processDir = $this->processLocation . $this->_pid;
  313. $processCmdFile = $processDir ;
  314. $processPwdFile = $processDir . '/pwd';
  315. // すべてのプロセスが配置されているディレクトリ
  316. if (!is_dir($this->processLocation)) {
  317. mkdir($this->processLocation, 0777);
  318. chmod($ processDir, 0777);
  319. }
  320. // 重複したプロセス レコードをクエリします
  321. $pDirObject = dir($this->processLocation);
  322. while ($pDirObject && (($pid = $pDirObject->read ()) !== false)) {
  323. if ($pid == '.' || $pid == '..' || intval($pid) != $pid) {
  324. continue;
  325. }
  326. $pDir = $this->processLocation . $pid;
  327. $pCmdFile = $pDir ;
  328. $pPwdFile = '/pwd';
  329. $pHeartFile . heart';
  330. // cmd check に基づいて同じパラメータでプロセスを開始します if (is_file($pCmdFile) &&rim(file_get_contents($pCmdFile)) == $command) {
  331. unlink($pCmdFile);
  332. unlink ($pPwdFile);
  333. unlink($pHeartFile);
  334. // 削除されたディレクトリにはキャッシュがあります
  335. usleep(1000);
  336. rmdir($pDir);
  337. }
  338. }
  339. // 新しいプロセスディレクトリ
  340. if (!is_dir ($processDir)) {
  341. mkdir($processDir, 0777);
  342. chmod($processDir, 0777);
  343. }
  344. // コマンドパラメータを書き込みます
  345. file_put_contents($processCmdFile, $command);
  346. file_put_contents($processPwdFile, $ _SERVER['PWD' ]);
  347. // 書き込みファイルはキャッシュされます
  348. usleep(1000);
  349. return true;
  350. }
  351. /**
  352. * _initProcessLocation
  353. * 初期化
  354. *
  355. * @return void
  356. */
  357. protected function _initProcessLocation() {
  358. $this ->processLocation = ROOT_PATH . '/app/data/proc';
  359. $this->processHeartLocation = $this->processLocation '/heart';
  360. }
  361. }
コードをコピー

関連ラベル:
ソース:php.cn
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート