进程之间的通讯,作为老牌的通讯方式:管道
管道分为: 无名管道和 有名管道
1、无名管道
popen 打开进程文件指针(单向管道)
pclose 关闭用popen打开的指向管道的指针
proc_open 打开一个用来输入和输出的文件指针(双向管道)
proc_close 管子资源文件
$desc=[
['pipe','r'],
['pipe','w'],
['file','/tmp/error.txt','a']
];
$cmd='cat';
$process=proc_open($cmd,$desc,$pipes);
if(!is_resource($process)){
exit('proc_open failure.');
}
fwrite($pipes[0],date('Y-m-d H:i:s'));
sleep(1);
echo 'daa';
$str=fread($pipes[1],100);
echo $str.PHP_EOL;
fclose($pipes[1]);
fclose($pipes[0]);
proc_close($process);
说明:$cmd =cat 直接打印数据
$desc=[
['pipe','r'],
['pipe','w'],
['file','/tmp/error.txt','a']
];
//$cmd='cat';
$cmd='php';
$process=proc_open($cmd,$desc,$pipes);
if(!is_resource($process)){
exit('proc_open failure.');
}
//fwrite($pipes[0],date('Y-m-d H:i:s'));
fwrite($pipes[0],'<?php print_r($_SERVER); ?>');
/**fwrite($pipes[0],'<?php echo time(); ?>');**/
fclose($pipes[0]);
//sleep(1);
//echo 'daa';
$str=stream_get_contents($pipes[1]);
echo $str.PHP_EOL;
fclose($pipes[1]);
proc_close($process);
这里的$cmd =php ,则说明要执行php文件Array
(
[HOSTNAME] => localhost.localdomain
[SELINUX_ROLE_REQUESTED] =>
[SHELL] => /bin/bash
[TERM] => xterm
[HISTSIZE] => 1000
[SSH_CLIENT] => 192.168.61.102 49385 22
[SELINUX_USE_CURRENT_RANGE] =>
[SSH_TTY] => /dev/pts/0
[USER] => root
[LS_COLORS] => rs=0:di=01;34:ln=01;36:mh=00:pi=40;33:so=01;35:do=01;35:bd=40;33;01:cd=40;33;01:or=40;31;01:mi=01;05;37;41:su=37;41:sg=30;43:ca=30;41:tw=30;42:ow=34;42:st=37;44:ex=01;32:*.tar=01;31:*.tgz=01;31:*.arj=01;31:*.taz=01;31:*.lzh=01;31:*.lzma=01;31:*.tlz=01;31:*.txz=01;31:*.zip=01;31:*.z=01;31:*.Z=01;31:*.dz=01;31:*.gz=01;31:*.lz=01;31:*.xz=01;31:*.bz2=01;31:*.tbz=01;31:*.tbz2=01;31:*.bz=01;31:*.tz=01;31:*.deb=01;31:*.rpm=01;31:*.jar=01;31:*.rar=01;31:*.ace=01;31:*.zoo=01;31:*.cpio=01;31:*.7z=01;31:*.rz=01;31:*.jpg=01;35:*.jpeg=01;35:*.gif=01;35:*.bmp=01;35:*.pbm=01;35:*.pgm=01;35:*.ppm=01;35:*.tga=01;35:*.xbm=01;35:*.xpm=01;35:*.tif=01;35:*.tiff=01;35:*.png=01;35:*.svg=01;35:*.svgz=01;35:*.mng=01;35:*.pcx=01;35:*.mov=01;35:*.mpg=01;35:*.mpeg=01;35:*.m2v=01;35:*.mkv=01;35:*.ogm=01;35:*.mp4=01;35:*.m4v=01;35:*.mp4v=01;35:*.vob=01;35:*.qt=01;35:*.nuv=01;35:*.wmv=01;35:*.asf=01;35:*.rm=01;35:*.rmvb=01;35:*.flc=01;35:*.avi=01;35:*.fli=01;35:*.flv=01;35:*.gl=01;35:*.dl=01;35:*.xcf=01;35:*.xwd=01;35:*.yuv=01;35:*.cgm=01;35:*.emf=01;35:*.axv=01;35:*.anx=01;35:*.ogv=01;35:*.ogx=01;35:*.aac=01;36:*.au=01;36:*.flac=01;36:*.mid=01;36:*.midi=01;36:*.mka=01;36:*.mp3=01;36:*.mpc=01;36:*.ogg=01;36:*.ra=01;36:*.wav=01;36:*.axa=01;36:*.oga=01;36:*.spx=01;36:*.xspf=01;36:
[PATH] => /usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/mysql5.6/bin:/usr/local/php/php7/bin:/root/bin
[MAIL] => /var/spool/mail/root
[_] => /usr/local/php/php7/bin/php
[PWD] => /home/song/php
[LANG] => en_US.UTF-8
[SELINUX_LEVEL_REQUESTED] =>
[HISTCONTROL] => ignoredups
[SSH_ASKPASS] => /usr/libexec/openssh/gnome-ssh-askpass
[HOME] => /root
[SHLVL] => 2
[LOGNAME] => root
[CVS_RSH] => ssh
[SSH_CONNECTION] => 192.168.61.102 49385 192.168.61.103 22
[LESSOPEN] => |/usr/bin/lesspipe.sh %s
[G_BROKEN_FILENAMES] => 1
[PHP_SELF] => Standard input code
[SCRIPT_NAME] => Standard input code
[SCRIPT_FILENAME] =>
[PATH_TRANSLATED] =>
[DOCUMENT_ROOT] =>
[REQUEST_TIME_FLOAT] => 1542807455.4841
[REQUEST_TIME] => 1542807455
[argv] => Array
(
[0] => Standard input code
)
[argc] => 1
)
2、有名管道
可以在两个独立的进程中独立通讯 。不再受制于父子进程,有名管道是一个文件,使用posix_mkfifo() 函数创建。这个函数有两个参数 第一个参数 文件路径(我们一般放在/tmp/目录下)第二个参数是maskmode 比如说 0644 、0755 这样的值。写数据、读数据 和我们操作普通文件是一样的。 fread($handle,100) 或 fgets($handle) 读取一行 fwrite($handle,$data) 使用fclose() 关闭资源
posix_mkfifo()
下面我们举个例子:
写入有名管道:pipe.php$file='/tmp/pipe';
if(!file_exists($file)){
posix_mkfifo($file,0644);
}
$handle=fopen($file,'w');
if(!$handle){
exit('create or open file failure.');
}
$count=0;
while($count<10){
fwrite($handle,$count."\n");
echo 'write '.$count.PHP_EOL;
sleep(1);
$count++;
}
fclose($handle);
unlink($file);
读有名管道:readpipe.php$file='/tmp/pipe';
if(!file_exists($file)){
exit("file not exists.\n");
}
$handle=fopen($file,'r');
while(true && !feof($handle)){
$str=trim(fgets($handle),PHP_EOL);
echo $str.PHP_EOL;
}
/*
while(true){
$str=trim(fgets($handle),PHP_EOL);
if(!empty($str)){
echo $str.PHP_EOL;
if($str=='exit'){
break;
}
}
}
*/
fclose($handle);
/**
在这里做一个说明,如果我想把有名管道的读取,做一个守护进程,应该怎么做?
我这里想在最外层 做一个 while(true)的循环,
判断文件是否存在,如果存在就执行任务,如果文件不存在,就在这里while循环着。
也不会退出程序。
**/
也可以直接使用linux的命令行: cat /tmp/pipe 来读取。
做个提醒:
场景1
我们在命令行中 执行 php pipe.php ,如果没有打开客户端读取,则写操作是一直处于阻塞的状态,直到有进程读取数据,才进行。
场景2
我们在命令行中 执行 php pipe.php ,打开的客户端正在读取,突然间中断,则 发送方继续发送,直到发送完毕结束。
会造成数据丢失,就不能收到全部数据,这个怎么容错?
正常通讯的方式,是可以收取到所有的数据,但这程序也不排除有其他问题吧。
3、无名管道与有名管道的区别
1、无名管道:无文件,只能在两个相关的两个进程之间使用,且有相同的祖先进程才可通讯。
2、有名管道:系统中有可见的管道文件,不想管的进程也能交换数据。