setName('chat') ->addArgument('action', Argument::OPTIONAL, "start|stop|restart|reload", 'start') ->addOption('host', 'H', Option::VALUE_OPTIONAL, 'the host of swoole server.', null) ->addOption('port', 'p', Option::VALUE_OPTIONAL, 'the port of swoole server.', null) ->addOption('daemon', 'd', Option::VALUE_NONE, 'Run the swoole server in daemon mode.') ->setDescription('chat Swoole Server for ThinkPHP'); } public function execute(Input $input, Output $output) { $action = $input->getArgument('action'); if (!in_array($action, ['start', 'stop', 'reload', 'restart'])) { $output->writeln("Invalid argument action:{$action}, Expected start|stop|restart|reload ."); return false; } //timely TIMELY $brand = <<writeln($brand . PHP_EOL); $this->init(); $this->$action(); } protected function init() { $this->config = Config::pull('swoole_server'); if (empty($this->config['pid_file'])) { $this->config['pid_file'] = Env::get('runtime_path') . 'swoole_server.pid'; } // 避免pid混乱 $this->config['pid_file'] .= '_' . $this->getPort(); } /** * 启动server * @access protected * @return void */ protected function start() { $pid = $this->getMasterPid(); if ($this->isRunning($pid)) { $this->output->writeln('swoole server process is already running.'); return false; } $this->output->writeln('Starting swoole server...'); if (!empty($this->config['swoole_class'])) { $class = $this->config['swoole_class']; if (class_exists($class)) { $swoole = new $class; if (!$swoole instanceof ThinkServer) { $this->output->writeln("Swoole Server Class Must extends \\think\\swoole\\Server"); return false; } } else { $this->output->writeln("Swoole Server Class Not Exists : {$class}"); return false; } } else { $host = $this->getHost(); $port = $this->getPort(); $type = !empty($this->config['type']) ? $this->config['type'] : 'socket'; $mode = !empty($this->config['mode']) ? $this->config['mode'] : SWOOLE_PROCESS; $sockType = !empty($this->config['sock_type']) ? $this->config['sock_type'] : SWOOLE_SOCK_TCP; switch ($type) { case 'socket': $swooleClass = 'Swoole\Websocket\Server'; break; case 'http': $swooleClass = 'Swoole\Http\Server'; break; default: $swooleClass = 'Swoole\Server'; } $swoole = new $swooleClass($host, $port, $mode, $sockType); // 开启守护进程模式 if ($this->input->hasOption('daemon')) { $this->config['daemonize'] = true; } foreach ($this->config as $name => $val) { if (0 === strpos($name, 'on')) { $swoole->on(substr($name, 2), $val); unset($this->config[$name]); } } // 设置服务器参数 $swoole->set($this->config); $this->output->writeln("Swoole {$type} server started: <{$host}:{$port}>" . PHP_EOL); $this->output->writeln('You can exit with `CTRL-C`'); // 启动服务 $swoole->start(); } } /** * 柔性重启server * @access protected * @return void */ protected function reload() { // 柔性重启使用管理PID $pid = $this->getMasterPid(); if (!$this->isRunning($pid)) { $this->output->writeln('no swoole server process running.'); return false; } $this->output->writeln('Reloading swoole server...'); Process::kill($pid, SIGUSR1); $this->output->writeln('> success'); } /** * 停止server * @access protected * @return void */ protected function stop() { $pid = $this->getMasterPid(); if (!$this->isRunning($pid)) { $this->output->writeln('no swoole server process running.'); return false; } $this->output->writeln('Stopping swoole server...'); Process::kill($pid, SIGTERM); $this->removePid(); $this->output->writeln('> success'); } protected function getHost() { if ($this->input->hasOption('host')) { $host = $this->input->getOption('host'); } else { $host = !empty($this->config['host']) ? $this->config['host'] : '0.0.0.0'; } return $host; } /** * 删除PID文件 * @access protected * @return void */ protected function removePid() { $masterPid = $this->config['pid_file']; if (is_file($masterPid)) { unlink($masterPid); } } protected function getPort() { if ($this->input->hasOption('port')) { $port = $this->input->getOption('port'); } else { $port = !empty($this->config['port']) ? $this->config['port'] : 9501; } return $port; } /** * 获取主进程PID * @access protected * @return int */ protected function getMasterPid() { $pidFile = $this->config['pid_file']; if (is_file($pidFile)) { $masterPid = (int)file_get_contents($pidFile); } else { $masterPid = 0; } return $masterPid; } /** * 判断PID是否在运行 * @access protected * @param int $pid * @return bool */ protected function isRunning($pid) { if (empty($pid)) { return false; } return Process::kill($pid, 0); } }