前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Linux进程通信之管道通信

Linux进程通信之管道通信

作者头像
北溟有鱼QAQ
发布2021-07-27 16:17:45
1.9K0
发布2021-07-27 16:17:45
举报
文章被收录于专栏:北溟有鱼QAQ北溟有鱼QAQ

父子进程管道通信

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 ok\r\n");
    }
}

$pid = pcntl_fork();

//子进程
if($pid == 0)
{
    //以读方式打开文件
    $fd = fopen($file,'r');
    //读取五个字节
    $data = fread($fd,5);
    //读到数据则打印
    if($data){
        fprintf(STDOUT,"read press pid=%d recv:%s\n",posix_getpid(),$data);
    }
    exit(0);
}
//以写方式打开文件
$fd = fopen($file,'w');
//写入五个字节
$len = fwrite($fd,'12345',5);

fprintf(STDOUT,"write process pid=%d,write len=%d\n",posix_getpid(),$len);

fclose($fd);

//回收子进程,避免变成僵尸进程
$pid = pcntl_wait($status);
if($pid > 0)
{
    fprintf(STDOUT,"子进程退出成功 pid=%d\n",$pid);

}

当通过运行代码时,我们可以发现的,当父进程写入数据后,子进程也会读到父进程写入的数据,但以上管道通信是以阻塞方式运行的,当没有数据时,进程则会阻塞不执行

非阻塞方式

代码语言:javascript
复制
$file = 'pipe_file';
//检测是否存在管道文件
if(!posix_access($file,POSIX_F_OK))
{
    //创建管道文件
    if(posix_mkfifo($file,0666))
    {
        fprintf(STDOUT,"create ok\r\n");
    }
}

$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:%s\n",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=%d\n",posix_getpid(),$len);

fclose($fd);

//回收子进程,避免变成僵尸进程
$pid = pcntl_wait($status);
if($pid > 0)
{
    fprintf(STDOUT,"子进程退出成功 pid=%d\n",$pid);

}

当加上函数stream_set_blocking以非阻塞方式运行后,会发现写进程并没有写进去,并且报了一个警告的错误,这个就是因为非阻塞模式,不管有没有接受到数据,都执行完毕退出导致的,下面我们再修改一下代码

非阻塞模式修改版

代码语言:javascript
复制
$file = 'pipe_file';
//检测是否存在管道文件
if(!posix_access($file,POSIX_F_OK))
{
    //创建管道文件
    if(posix_mkfifo($file,0666))
    {
        fprintf(STDOUT,"create ok\r\n");
    }
}

$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:%s\n",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=%d\n",posix_getpid(),$len);

fclose($fd);

//回收子进程,避免变成僵尸进程
$pid = pcntl_wait($status);
if($pid > 0)
{
    fprintf(STDOUT,"子进程退出成功 pid=%d\n",$pid);

}

通过执行结果发现,到循环了1400多次后,写进程写入数据了,读进程读到数据后并退出了

注意

当读进程还在读数据的时候,写进程关闭,此时写进程则会无法写入数据,并且会发送一个中断信号SIGPIPE,此时需要自己进行处理。有想法的同学可以自己尝试写一下,自己实现信号调度并打印信号处理

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2021-07-23 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 父子进程管道通信
    • Linux进程通信的几种方式
      • 阻塞代码
        • 非阻塞方式
          • 非阻塞模式修改版
            • 注意
            相关产品与服务
            领券
            问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档