进程间通信-管道

概括

管道是Linux支持的最初Unix IPC形式之一,管道的实质是一个内核缓冲区,管道的作用正如其名,需要通信的两个进程在管道的两端,进程利用管道传递信息。管道对于管道两端的进程而言,就是一个文件,但是这个文件比较特殊,它不属于文件系统并且只存在于内存中。

[root@VM-0-13-centos ssh]# file fifo_x
fifo_x: fifo (named pipe)

管道依据是否有名字分为匿名管道和命名管道(有名管道),这两种管道有一定的区别。
匿名管道有几个重要的限制:

  1. 管道是半双工的,数据只能在一个方向上流动,A进程传给B进程,不能反向传递
  2. 管道只能用于父子进程或兄弟进程之间的通信,即具有亲缘关系的进程。
    命名管道允许没有亲缘关系的进程进行通信。命名管道不同于匿名管道之处在于它提供了一个路径名与之关联,这样一个进程即使与创建有名管道的进程不存在亲缘关系,只要可以访问该路径,就能通过有名管道互相通信。

上PHP代码

PHP只提供了命名管道的封装。

父子进程管道通信(阻塞)

<?php
$file = "fifo_x";
if(!posix_access($file, POSIX_F_OK)){
    // 如果没有 创建管道文件
    if(posix_mkfifo($file, 0666)){
        fprintf(STDOUT, "创建OK \n");
    }
}

$pid = pcntl_fork();
if($pid == 0){
    $fd = fopen($file, "r");
    // 如果管道中没有数据 则会持续阻塞
    $data = fread($fd, 5);
    if($data){
        fprintf(STDOUT, "子进程 pid = %d read:%s \n", getmypid(), $data);
    }
    exit(0);
}

$fd = fopen($file, "w");
$len = fwrite($fd, "hello", 5);
fprintf(STDOUT,"pid = %d len = %d \n", getmypid(), $len);
fclose($fd);

$pid = pcntl_wait($status);
if($pid > 0){
    fprintf(STDOUT,"子进程退出 pid = %d \n", $pid);
}

父子进程管道通信(非阻塞)

<?php
$file = "fifo_x";
if(!posix_access($file, POSIX_F_OK)){
    if(posix_mkfifo($file, 0666)){
        fprintf(STDOUT, "创建OK \n");
    }
}

$pid = pcntl_fork();
if($pid == 0){
    $fd = fopen($file, "r");
    // 设置非阻塞读
    stream_set_blocking($fd, 0);
    while (1){
        $data = fread($fd, 5);
        if($data){
            fprintf(STDOUT, "子进程 pid = %d read:%s \n", getmypid(), $data);
            exit(0);
        }else{
            fprintf(STDOUT, "子进程 pid = %d 没有数据 \n", getmypid());
        }
        sleep(1);
    }
}

$fd = fopen($file, "w");
sleep(5);
$len = fwrite($fd, "hello", 5);
fprintf(STDOUT,"父进程 pid = %d len = %d \n", getmypid(), $len);
fclose($fd);

$pid = pcntl_wait($status);
if($pid > 0){
    fprintf(STDOUT,"子进程退出 pid = %d \n", $pid);
}

读端关闭产生 SIGPIPE 信号

<?php
$file = "fifo_x";
// 捕获产生的信号 回收进程 退出主进程
pcntl_signal(SIGPIPE, function ($signal){
    fprintf(STDOUT, "进程 pid = %d 有信号 %d \n", getmypid(), $signal);
    $pid = pcntl_wait($status, WNOHANG);
    if($pid > 0){
        fprintf(STDOUT,"子进程回收 pid = %d \n", $pid);
        exit();
    }
});

if(!posix_access($file, POSIX_F_OK)){
    if(posix_mkfifo($file, 0666)){
        fprintf(STDOUT, "创建OK \n");
    }
}
$pid = pcntl_fork();
if($pid == 0){
    $fd = fopen($file, "r");
    $i = 0;
    stream_set_blocking($fd, 0);
    while (1){
        $data = fread($fd, 5);
        if($data){
            $i++;
            fprintf(STDOUT, "子进程 pid = %d read:%s \n", getmypid(), $data);
            if($i == 5){    //读取五次 关闭子进程
                break;
            }
        }
    }
    exit();
}
$fd = fopen($file, "w");
while (1){
    pcntl_signal_dispatch();
    $len = fwrite($fd, "hello", 5);
    sleep(1);
}

非血缘进程通信

<?php
// 接收进程
$file = "fifo_x";

if(!posix_access($file, POSIX_F_OK)){
    if(posix_mkfifo($file, 0666)){
        fprintf(STDOUT, "创建OK \n");
    }
}

$fd = fopen($file, "r");
// 非血缘进程通信 必须开启非阻塞
stream_set_blocking($fd, 0);
while (1){
    $data = fread($fd, 128);
    if($data){
        fprintf(STDOUT, "接受 %s \n", $data);
    }
}
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇