2013-09-16 3 views
3

다음 스크립트는 /dev/shm/test에 새 파일을 모니터링하고 이에 대한 정보를 실시간으로 출력합니다.proc_open 좀비 프로세스가 수행

사용자가 브라우저를 닫을 때 inotifywait 프로세스가 열린 상태로 유지되는 등의 문제가 있습니다.

이를 방지 할 수있는 방법이 있습니까?

<?php 
$descriptorspec = array(
    0 => array("pipe", "r"), // stdin is a pipe that the child will read from 
    1 => array("pipe", "w"), // stdout is a pipe that the child will write to 
    2 => array("pipe", "a") // stderr is a file to write to 
); 

$process = proc_open('inotifywait -mc -e create /dev/shm/test/', $descriptorspec, $pipes); 

if (is_resource($process)) { 

    header("Content-type: text/html;charset=utf-8;"); 
    ob_end_flush(); //ends the automatic ob started by PHP 
    while ($s = fgets($pipes[1])) { 
    print $s; 
    flush(); 
    } 
    fclose($pipes[1]); 
    fclose($pipes[0]); 
    fclose($pipes[2]); 

    // It is important that you close any pipes before calling 
    // proc_close in order to avoid a deadlock 
    $return_value = proc_close($process); 

    echo "command returned $return_value\n"; 
} 
?> 
+0

그럼 코드가 무한 루프를 포함 사용할 수 있습니다. 왜 당신은 그것이 끝없는 반복을하지 않을 것이라고 기대합니까? 또한 : 어떤 SAPI를 사용하고 있습니까? 예를 들어 CLI에서 해당 스크립트를 시작하고 Ctrl + C로 중단하면 어떻게됩니까? "아동 과정"이 살해 되었습니까? 'proc_open'은 자식 프로세스 또는 독립적 인 프로세스를 오픈합니까? 'fgets'로 시간 제한은 무엇입니까? STDOUT에서 읽지 않아도되는 것이 있다면 얼마나 오래 기다려야합니까? – hakre

+0

@hakre 콘솔 모드에서 Ctrl + C를 사용하여 inotifywait 프로세스가 종료되었음을 확인할 수 있습니다.fgets는 Jon의 대답처럼'connection_aborted()'와'proc_terminate()'를 검사하려고 시도했기 때문에 시간 초과가 없었습니다. PHP는 출력을 시도한 후에 만 ​​연결이 중단되었다는 것을 알게되므로 이상하게 여겨집니다. 뭔가 (나는). 또한 이러한 함수를 확인하지 않고도 스크립트는 윈도우로드를 취소 할 때 종료되어야합니다. 그렇습니까? – JorgeeFG

+0

사용중인 PHP 버전은 무엇입니까? – Omiga

답변

0

당신은 사용자가 브라우저 창을 닫을 때 스크립트가 실행을 중지하지 않도록 지정 ignore_user_abort를 사용할 수 있습니다. 즉, 문제의 절반을 해결할 것입니다, 그래서 창은이 질서 정연하게 모든 것을 종료해야하는시기를 결정하는 connection_aborted로 루프 내에서 닫힌 경우 당신은 또한 확인해야합니다

header("Content-type: text/html;charset=utf-8;"); 
ignore_user_abort(true); 
ob_end_flush(); //ends the automatic ob started by PHP 
while ($s = fgets($pipes[1])) { 
    print $s; 
    flush(); 
    if (connection_aborted()) { 
     proc_terminate($process); 
     break; 
    } 
} 
+0

고마워, 그게 효과가 있니? 나는 당신이 나에게 말한 것의 모든 조합을 시도했지만 운이 없었습니다. 과정은 열려 있습니다. 출력을 생성하기 위해 브라우저를 취소 한 후에도 새로운 파일을 만들었습니다. PHP가 연결이 중단되었지만 운이 없다는 것을 알려줍니다. – JorgeeFG

+0

@ Jorge : 사실 그것은 나에게도 효과가 없다. 불행히도 지금 당장이 문제를 조사 할 수는 없지만 나중에 다시 생각해 볼 것입니다. – Jon

+0

뭔가 이상합니다. 어쩌면 알 수없는 (적어도 나를 위해) 언어 때문에'$ s = fgets ($ pipes [1]) '에 붙어있을 수 있습니다. – JorgeeFG

0

이 도움이됩니까? 이 라인을 읽을 수있을 때까지 다음가 표준 오류 및 표준 출력에 이벤트 정보 및 fgets()출력 진단 정보가 대기하는 것이다 변경 파일 /dev/shm/test/ 일어날 때까지 inotifywait가 대기 때문이다

$proc_info = proc_get_status($process); 
pcntl_waitpid($proc_info['pid']); 
1

: $length - 1 바이트 (두 번째 매개 변수) 이 읽 혔을 때 읽기가 끝나거나 반환 값에 포함 된 개행 또는 EOF (둘 중 빠른 날짜가 적용되는 경우)가 종료됩니다. 길이가 지정되어 있지 않은 경우는, 행의 마지막에이를 때까지 스트림로부터 읽기를 계속합니다.

그래서 기본적으로, 당신은 stream_set_blocking($pipes[1], 0) 비 블록 모드가 자식 프로세스의 표준 출력 파이프에서 데이터를 읽어, 또는 stream_select()와 그 파이프에 데이터가있는 경우 수동으로 확인합니다.

ignore_user_abort(true)으로 사용자 중단을 무시해야합니다.

0

inotifywait은 기본적으로 종료되지 않는 자체 프로세스로 실행되므로 KILL 신호를 보내야합니다. cli에서 스크립트를 실행하면 Ctrl + C 신호도 inotifywait 프로세스로 전송되지만 웹 서버에서 실행 중일 때는 해당 신호가 없습니다.

register_shutdown_function 또는 __destruct에 의해 호출되는 함수에서 신호를 보냅니다.

주위에 도움을 줄 수 proc_open이 간단한 래퍼 :

class Proc 
{ 
    private $_process; 
    private $_pipes; 

    public function __construct($cmd, $descriptorspec, $cwd = null, $env = null) 
    { 
     $this->_process = proc_open($cmd, $descriptorspec, $this->_pipes, $cwd, $env); 
     if (!is_resource($this->_process)) { 
      throw new Exception("Command failed: $cmd"); 
     } 
    } 

    public function __destruct() 
    { 
     if ($this->isRunning()) { 
      $this->terminate(); 
     } 
    } 

    public function pipe($nr) 
    { 
     return $this->_pipes[$nr]; 
    } 

    public function terminate($signal = 15) 
    { 
     $ret = proc_terminate($this->_process, $signal); 
     if (!$ret) { 
      throw new Exception("terminate failed"); 
     } 
    } 

    public function close() 
    { 
     return proc_close($this->_process); 
    } 

    public function getStatus() 
    { 
     return proc_get_status($this->_process); 
    } 

    public function isRunning() 
    { 
     $st = $this->getStatus(); 
     return $st['running']; 
    } 
} 

$descriptorspec = array(
    0 => array("pipe", "r"), // stdin is a pipe that the child will read from 
    1 => array("pipe", "w"), // stdout is a pipe that the child will write to 
    2 => array("pipe", "a") // stderr is a file to write to 
); 
$proc = new Proc('inotifywait -mc -e create /dev/shm/test/', $descriptorspec); 

header("Content-type: text/html;charset=utf-8;"); 
ob_end_flush(); //ends the automatic ob started by PHP 
$pipe = $proc->pipe(1); 
while ($s = fgets($pipe)) { 
    print $s; 
    flush(); 
} 
fclose($pipe); 

$return_value = proc->close($process); 

echo "command returned $return_value\n"; 

아니면 exactly the same (및 기타 유용한 일을)하지 심포니 프로세스 구성 요소

관련 문제