PHP 파이프라인 통신
내 블로그: http://www.cnblogs.com/nickbai/
내 GitHub: https://github.com/nick-bai
프로세스 간 통신을 위한 PHP 메시지 큐, 파이프, 공유 메모리, 소켓, 신호 등 여러 가지 방법이 있습니다. 이번 글에서는 유명한 파이프를 통해 그 방법을 소개합니다.
PIPE
파이프는 약어 간의 통신 데이터를 전달하는 데 사용됩니다. 이해를 돕기 위해 파이프를 파일과 비교할 수 있습니다. 프로세스 A는 파이프 P에 데이터를 쓴 다음 프로세스 B는 파이프 P에서 데이터를 읽습니다. PHP에서 제공하는 파이프라인 작업 API는 기본적으로 파일 작업을 위한 API와 동일합니다. 파이프라인을 생성하기 위해 posix_mkfifo 함수를 사용한다는 점을 제외하면 읽기 및 쓰기 작업은 파일 작업 함수와 동일합니다. 물론 파일을 직접 사용하여 파이프를 시뮬레이션할 수 있지만 파이프의 기능을 사용할 수는 없습니다.
파이프를 통한 통신의 일반적인 아이디어는 먼저 파이프를 만든 다음 하위 프로세스가 파이프에 정보를 쓰고 상위 프로세스가 파이프에서 정보를 읽는 것입니다. 하위 프로세스는 직접 통신할 수 있습니다. <?php<br>/**<br> * author: NickBai<br> * createTime: 2016/12/2 0002 上午 11:12<br> */<br>//创建管道<br>$pipePath = "/tmp/test.pipe";<br>if( !file_exists( $pipePath ) ){<br> if( !posix_mkfifo( $pipePath, 0666 ) ){<br> exit('make pipe false!' . PHP_EOL);<br> }<br>}<br><br>//创建进程,子进程写管道,父进程读管道<br>$pid = pcntl_fork();<br><br>if( $pid == 0 ){<br> //子进程写管道<br> $file = fopen( $pipePath, 'w' );<br> fwrite( $file, 'hello world' );<br> sleep(1);<br> exit();<br>}else{<br> //父进程读管道<br> $file = fopen( $pipePath, 'r' );<br> //stream_set_blocking( $file, False ); //设置成读取非阻塞<br> echo fread( $file, 20 ) . PHP_EOL;<br><br> pcntl_wait($status); //回收子进程<br>}
/** * 작성자: NickBai
* createTime: 2016/12/2 0002 11:12 AM
*/
//파이프 생성
$pipePath = "/tmp/test.pipe";
if( !file_exists( $pipePath ) ){
if( !posix_mkfifo( $pipePath, 0666 ) ){
exit('파이프를 거짓으로 만드세요!' . PHP_EOL);
}
}
//만들기 프로세스, 하위 프로세스가 파이프를 쓰고, 상위 프로세스가 파이프를 읽습니다.
$pid = pcntl_fork();
if( $pid == 0 ){ //자식 프로세스가 파이프를 씁니다. 파이프
$file = fopen( $pipePath, 'w' );
fwrite( $file, 'hello world' );
sleep(1);
exit();} else{
/ /상위 프로세스가 파이프를 읽습니다
$file = fopen( $pipePath, 'r' );
//stream_set_blocking( $file, False ) //비차단 읽기로 설정 echo fread( $file , 20 ) . PHP_EOL;<br><br> pcntl_wait($status); //하위 프로세스 재활용<br>}
참고: 이 코드는 Linux에서만 실행될 수 있습니다. php -cli 모드에서만 실행할 수 있습니다.
7행 : 일반 파일과 다르지 않은 파이프라인의 경로를 지정합니다.
9행: posix_mkfifo 함수를 통해 파이프를 생성하고 읽기 및 쓰기 권한을 0666으로 설정합니다. 15행: pcntl_fork 함수를 통해 하위 프로세스를 생성합니다. 이제부터 프로그램은 두 가지 프로세스로 실행됩니다. pcntl_fork 함수는 일단 호출되면 여러 개의 반환 값을 갖습니다. 상위 프로세스에서: 하위 프로세스의 ID를 반환합니다. 이 값은 0보다 큽니다. 하위 프로세스에서는 0을 반환합니다. -1이 반환되면 생성 프로세스가 실패했음을 나타냅니다. 17행: 두 프로세스는 현재 프로세스에서 얻은 서로 다른 $pid 값을 기반으로 서로 다른 분기에 들어갑니다. 18~22행: 하위 프로세스가 파이프를 열고 hello world를 쓴 다음 절전 모드로 들어가고 절전 모드가 끝나면 종료됩니다. 25~29행: 상위 프로세스가 파이프를 열고 읽은 후 마지막으로 코드 29행을 실행하여 하위 프로세스를 재활용합니다. 여기에는 두 개의 차단된 위치가 있습니다. 첫 번째는 기본 읽기 위치입니다. 데이터가 반환되기 전에 하위 프로세스가 종료 명령을 내릴 때까지 기다려야 합니다. 프로세스를 재활용하는 pcntl_wait 방법도 있습니다. 프로세스가 종료될 때까지 기다리십시오. Linux에서 다음 코드를 실행하세요. 프로그램이 1초 동안 차단된 다음 hello world를 출력하는 것을 볼 수 있습니다. 코드의 26번째 줄을 열고 27번째 줄을 var_dump(fread( $file, 20 )) 으로 변경하면 프로그램을 실행할 때: 프로그램은 즉시 빈 문자열을 출력하고 종료하기 전에 1초 동안 기다립니다. 그 이유는. 읽기가 비차단인 경우 상위 프로세스가 정보를 읽을 때 정보가 즉시 사용 가능할 때까지 기다리지 않고 파이프라인에 정보가 없으면 즉시 반환됩니다. 그런 다음 29행이 자식 프로세스를 재활용하기 위해 실행되면 자식 프로세스가 종료될 때까지 차단하고 기다립니다. 간단한 실제 사례를 살펴보겠습니다. 두 개의 하위 프로세스가 파일에 정보를 씁니다. 상위 프로세스는 파일 쓰기가 완료되었는지 모니터링하고 감지하는 일을 담당합니다. 여기서 상위 프로세스와 하위 프로세스는 파이프를 통해 통신하여 쓰기가 완료되었는지 확인합니다. if( !posix_mkfifo( $pipePath, 0666 ) ){
exit("파이프 실패 n 만들기");
}
}
//파일을 쓰기 위한 두 개의 하위 프로세스 생성
for( $i = 0; $i < 2; $i++ ){
$pid = pcntl_fork();
if( $pid == 0 ){
file_put_contents( './pipe.log', $i . " write Pipen", FILE_APPEND ) //파일 쓰기
$file = fopen( $pipePath, 'w' ) ;
who’ who who who’s who’s who’s writing, fwrite( $file, $i . "n" ) //로고를 파이프라인에 작성하면 로고 작성이 완료됩니다.
fclose( $file );
exit(); //자식 프로세스 종료
}
}
//부모 프로세스에서 수행해야 할 작업은 다음과 같습니다.
//1, 파이프에서 쓰기 상태를 읽고 완전히 쓰여졌는지 확인
//2. 작성된 파일을 복사합니다
//3. 파이프를 삭제합니다
//4. 🎜>
$file = fopen( $pipePath, 'r' );
$line = 0;
while(1){
$end = fread( $file, 1024);
foreach( str_split ( $end ) as $c) {
if ( "n" == $c ) {
$line++;
}
}
if( $ line == 2 ){
copy( './pipe.log', './pipe_copy.log' );
fclose( $file );
unlink( $pipePath );
pcntl_wait ( $status ) ;
종료("ok n");
}
}