/** * * 添加一个任务 * * @param int $time_long 多长时间运行一次 单位秒 * @param callback $func 任务运行的函数或方法 * @param mix $args 任务运行的函数或方法使用的参数 * @return void */ public static function add($time_long, $func, $args = array(), $persistent = true) { if ($time_long <= 0) { return false; } if (!is_callable($func) && class_exists('ServerLog')) { ServerLog::add(var_export($func, true) . "not callable\n"); return false; } $time_now = time(); $run_time = $time_now + $time_long; if (!isset(self::$tasks[$run_time])) { self::$tasks[$run_time] = array(); } self::$tasks[$run_time][] = array($func, $args, $persistent, $time_long); }
/** * debug * @param sring $str */ protected function notice($str) { ServerLog::add('[' . get_class($this) . '] ' . $str); }
/** * notice,记录到日志,同时打印到telnet客户端(如果有telnet链接的话) * @param string $msg * @param bool $display */ protected static function notice($msg, $display = false) { ServerLog::add("Server notice:" . $msg); Telnet::sendToAllClient($msg . "\n"); if ($display) { if (self::$serverStatus == self::STATUS_STARTING) { echo $msg . "\n"; } } }
/** * 处理收到的管理员命令 * @param event_buffer $event_buffer * @param int $fd * @return boolean */ public static function dealCmd($connection, $length, $buffer, $fd = null) { // 管理员断开 if ($length == 0) { self::closeClient($fd); return; } self::$currentFd = $fd; $buffer = trim($buffer); $ip = self::getRemoteIp(); if ($ip != '127.0.0.1' && $buffer == 'status') { ServerLog::add("IP:{$ip} {$buffer}"); } // 判断是否认证过 self::$adminAuth[$fd] = !isset(self::$adminAuth[$fd]) ? 0 : self::$adminAuth[$fd]; if (self::$adminAuth[$fd] < 3) { if ($buffer != 'P@ssword') { if (++self::$adminAuth[$fd] >= 3) { self::sendToClient("Password Incorrect \n"); self::closeClient($fd); } self::sendToClient("Please Try Again\n"); return; } else { self::$adminAuth[$fd] = time(); self::sendToClient("Hello Admin \n"); return; } } $pid_worker_name_map = PHPServer::getPidWorkerNameMap(); // 单独停止某个worker进程 if (preg_match("/kill (\\d+)/", $buffer, $match)) { $pid = $match[1]; if (isset($pid_worker_name_map[$pid])) { self::sendToClient("Kill Pid {$pid} "); PHPServer::addToRestartWorkers(array($pid)); PHPServer::restartWorkers(); } else { self::sendToClient("Pid Not Exsits\n"); } return; } // 打印某个变量 print_r $current if (preg_match("/debug (.*)/", $buffer, $match)) { $var = trim($match[1]); $var = str_replace('$', '', $var); if (!$var) { self::sendToClient("Uesage debug var_name\n"); return; } self::sendToClient(PHPServer::debugVar($var) . "\n"); return; } switch ($buffer) { // 展示统计信息 case 'status': $status = PHPServer::getServerStatusInfo(); $worker_pids = PHPServer::getWorkerPids(); $loadavg = sys_getloadavg(); self::sendToClient("---------------------------------------GLOBAL STATUS--------------------------------------------\n"); self::sendToClient('start time:' . date('Y-m-d H:i:s', $status['start_time']) . ' run ' . floor((time() - $status['start_time']) / (24 * 60 * 60)) . ' days ' . floor((time() - $status['start_time']) % (24 * 60 * 60) / (60 * 60)) . " hours \n"); self::sendToClient('load average: ' . implode(", ", $loadavg) . "\n"); self::sendToClient(count(self::$connections) . ' users ' . count($worker_pids) . ' workers ' . count($pid_worker_name_map) . " processes\n"); self::sendToClient(str_pad('worker_name', self::$maxWorkerNameLength) . " exit_status exit_count\n"); foreach ($worker_pids as $worker_name => $pid_array) { if (isset($status['err_info'][$worker_name])) { foreach ($status['err_info'][$worker_name] as $exit_status => $exit_count) { self::sendToClient(str_pad($worker_name, self::$maxWorkerNameLength) . " " . str_pad($exit_status, 16) . " {$exit_count}\n"); } } else { self::sendToClient(str_pad($worker_name, self::$maxWorkerNameLength) . " " . str_pad(0, 16) . " 0\n"); } } PHPServer::sendCmdToAll(Cmd::CMD_REPORT_STATUS_FOR_MASTER); self::sendToClient("---------------------------------------PROCESS STATUS-------------------------------------------\n"); self::sendToClient("pid\tmemory proto port timestamp " . str_pad('worker_name', self::$maxWorkerNameLength) . " " . str_pad('total_request', 13) . " " . str_pad('recv_timeout', 12) . " " . str_pad('proc_timeout', 12) . " " . str_pad('packet_err', 10) . " " . str_pad('thunder_herd', 12) . " " . str_pad('client_close', 12) . " " . str_pad('send_fail', 9) . " " . str_pad('throw_exception', 15) . " suc/total\n"); break; // 停止server // 停止server case 'stop': PHPServer::stop(); break; // 平滑重启server // 平滑重启server case 'reload': PHPServer::addToRestartWorkers(array_keys($pid_worker_name_map)); PHPServer::restartWorkers(); self::sendToClient("Restart Workers "); break; // admin管理员退出 // admin管理员退出 case 'quit': self::sendToClient("Admin Quit\n"); self::$event->delAll(self::$connections[self::$currentFd]); fclose(self::$connections[self::$currentFd]); unset(self::$connections[self::$currentFd], self::$adminAuth[self::$currentFd]); break; case 'debug': self::sendToClient("Uesage debug var_name\n"); break; case '': break; default: self::sendToClient("Unkonw CMD \nAvailable CMD:\n status show server status\n stop stop server\n reload graceful restart server\n quit quit and close connection\n kill pid kill the worker process of the pid\n"); } }
public function onAlarm() { $ob_content = ob_get_contents(); if ($ob_content) { ServerLog::add('StatisticService:ob_content:' . $ob_content); ob_clean(); } }
/** * 检查文件更新时间,如果有更改则平滑重启服务(开发的时候用到) * @return void */ public function checkFilesModify() { if ($this->isReloading) { return; } foreach ($this->filesToInotify as $file => $mtime) { clearstatcache(); $stat = @stat($file); if (false === $stat) { unset($this->filesToInotify[$file]); continue; } $mtime_now = $stat['mtime']; if ($mtime != $mtime_now) { ServerLog::add("{$file} updated and reload workers"); $master_pid = file_get_contents(PID_FILE); if ($master_pid) { posix_kill($master_pid, SIGUSR2); $this->isReloading = true; } } } }