父子进程管道通信
Linux进程通信的几种方式
- 管道通信
- 中断信号
- 共享内存、消息队列
- Unix Socket
我们PHP中所使用的workman、swoole 或者其他语言当中的进行通信也是无非以上的几种方式
阻塞代码
代码语言:javascript复制$file = 'pipe_file';
//检测是否存在管道文件
if(!posix_access($file,POSIX_F_OK))
{
//创建管道文件
if(posix_mkfifo($file,0666))
{
fprintf(STDOUT,"create okrn");
}
}
$pid = pcntl_fork();
//子进程
if($pid == 0)
{
//以读方式打开文件
$fd = fopen($file,'r');
//读取五个字节
$data = fread($fd,5);
//读到数据则打印
if($data){
fprintf(STDOUT,"read press pid=%d recv:%sn",posix_getpid(),$data);
}
exit(0);
}
//以写方式打开文件
$fd = fopen($file,'w');
//写入五个字节
$len = fwrite($fd,'12345',5);
fprintf(STDOUT,"write process pid=%d,write len=%dn",posix_getpid(),$len);
fclose($fd);
//回收子进程,避免变成僵尸进程
$pid = pcntl_wait($status);
if($pid > 0)
{
fprintf(STDOUT,"子进程退出成功 pid=%dn",$pid);
}
当通过运行代码时,我们可以发现的,当父进程写入数据后,子进程也会读到父进程写入的数据,但以上管道通信是以阻塞方式运行的,当没有数据时,进程则会阻塞不执行
非阻塞方式
代码语言:javascript复制$file = 'pipe_file';
//检测是否存在管道文件
if(!posix_access($file,POSIX_F_OK))
{
//创建管道文件
if(posix_mkfifo($file,0666))
{
fprintf(STDOUT,"create okrn");
}
}
$pid = pcntl_fork();
//子进程
if($pid == 0)
{
//以读方式打开文件
$fd = fopen($file,'r');
//非阻塞方式
stream_set_blocking($fd,0);
//读取五个字节
$data = fread($fd,5);
//读到数据则打印
if($data){
fprintf(STDOUT,"read press pid=%d recv:%sn",posix_getpid(),$data);
}
exit(0);
}
//以写方式打开文件
$fd = fopen($file,'w');
//非阻塞方式
stream_set_blocking($fd,0);
//写入五个字节
$len = fwrite($fd,'12345',5);
fprintf(STDOUT,"write process pid=%d,write len=%dn",posix_getpid(),$len);
fclose($fd);
//回收子进程,避免变成僵尸进程
$pid = pcntl_wait($status);
if($pid > 0)
{
fprintf(STDOUT,"子进程退出成功 pid=%dn",$pid);
}
当加上函数stream_set_blocking以非阻塞方式运行后,会发现写进程并没有写进去,并且报了一个警告的错误,这个就是因为非阻塞模式,不管有没有接受到数据,都执行完毕退出导致的,下面我们再修改一下代码
非阻塞模式修改版
代码语言:javascript复制$file = 'pipe_file';
//检测是否存在管道文件
if(!posix_access($file,POSIX_F_OK))
{
//创建管道文件
if(posix_mkfifo($file,0666))
{
fprintf(STDOUT,"create okrn");
}
}
$pid = pcntl_fork();
//子进程
if($pid == 0)
{
//以读方式打开文件
$fd = fopen($file,'r');
stream_set_blocking($fd,0);
$i = 0;
//循环读取数据,读到数据后才退出
while (1)
{
$i ;
//打印循环了多少次
echo $i.PHP_EOL;
//读取五个字节
$data = fread($fd,5);
//读到数据则打印
if($data){
fprintf(STDOUT,"read press pid=%d recv:%sn",posix_getpid(),$data);
break;
}
}
exit(0);
}
//以写方式打开文件
$fd = fopen($file,'w');
stream_set_blocking($fd,0);
//写入五个字节
$len = fwrite($fd,'12345',5);
fprintf(STDOUT,"write process pid=%d,write len=%dn",posix_getpid(),$len);
fclose($fd);
//回收子进程,避免变成僵尸进程
$pid = pcntl_wait($status);
if($pid > 0)
{
fprintf(STDOUT,"子进程退出成功 pid=%dn",$pid);
}
通过执行结果发现,到循环了1400多次后,写进程写入数据了,读进程读到数据后并退出了
注意
当读进程还在读数据的时候,写进程关闭,此时写进程则会无法写入数据,并且会发送一个中断信号SIGPIPE,此时需要自己进行处理。有想法的同学可以自己尝试写一下,自己实现信号调度并打印信号处理