public function command_start($params) { $jobname = $params['jobname']; $setting = $this->config->get($jobname); $command = $setting['command']; $cmdparams = $setting['params']; $buffersize = $setting['buffersize']; $writelog = $setting['writelog']; $pid = $this->shm_process_getpid($jobname); if ($pid) { // 检查进程是否正在运行 if ($this->process_exists($pid)) { $this->client_return('FAILED'); $this->server_echo("FAILED. (process \"{$jobname}\"({$pid}) has already exist.)"); return FALSE; } else { // 检查进程是否回收结束 if ($this->shm_process_getpid($jobname)) { $this->client_return('FAILED'); $this->server_echo("FAILED. (process \"{$jobname}\"({$pid}) is still exiting.)"); return FALSE; } } } if (!file_exists($command)) { // 文件不存在 $this->client_return('FAILED'); $this->server_echo("FAILED. (command path \"{$command}\" does not exist.)"); return FALSE; } // 新建孙子进程 $pid = pcntl_fork(); if ($pid == -1) { $this->client_return('FAILED'); $this->server_echo('pcntl_fork() failed.'); return FALSE; } else { if ($pid) { pcntl_waitpid($pid, $status); return TRUE; } } // 子进程 $t_pid = pcntl_fork(); if ($t_pid == -1) { $this->client_return('FAILED'); $this->server_echo('pcntl_fork() failed.'); return FALSE; } else { if ($t_pid) { exit; } } // 孙子进程 $this->jobname = $jobname; $this->writelog = $writelog; $this->buffersize = $buffersize; $newline = !isset($params['newline']) ? TRUE : $params['newline']; if (ProcessContainer::dup2_available()) { // 使用 dup2 手工配置管道定向 } else { // 需要在proc_open前关闭socket,否则会被proc_open进程继承,导致socket端口被占用 $this->client_return('OK'); $this->server_echo('OK', $newline); $this->socket_close(); } $process = new ProcessContainer($command, $cmdparams, TRUE); $process->register_output_handler(array($this, 'process_output_handler')); $process->register_error_handler(array($this, 'process_error_handler')); $process->register_exit_handler(array($this, 'process_exit_handler')); $process->register_child_init_handler(array($this, 'process_child_init_handler')); if (!$process->start()) { if (ProcessContainer::dup2_available()) { $this->client_return('FAILED'); $this->server_echo('FAILED. (output_buffer init failed.)'); $this->socket_close(); } return FALSE; } // 进程配置写入共享内存 $process_pid = $process->get_pid(); $this->shm_process_updatepid($jobname, $process_pid); // 创建共享变量用于输出缓冲 $output_buffer = array(); if (!$this->shm->put_var('ob_' . $jobname, $output_buffer, TRUE)) { if (ProcessContainer::dup2_available()) { $this->client_return('FAILED'); $this->server_echo('FAILED. (output_buffer init failed.)'); $this->socket_close(); } return FALSE; } if (ProcessContainer::dup2_available()) { $this->client_return('OK'); $this->server_echo('OK', $newline); $this->socket_close(); } $process->loop_read(); exit; }