进程之间通信之匿名管道(PIPE)和有名管道(FIFO)


进程之间通信手段有哪些?
就实现手段上来看,有以下几种:
(1) 匿名管道(有亲缘关系进程)
(2) 有名管道(无亲缘也可以)
(3) 消息队列
(4) 共享内存
(5) 信号量
(6) 文件(不推荐)
(7) socket套接字

我们来分析以下匿名管道和有名管道进行进程之间通信的方法:

匿名管道

匿名管道用于具有血缘关系之间的进程进行通信。
首先,说一下管道的特点:
1、内核缓冲区
2、非文件
3、不占用磁盘空间
4、两部分:读端和写端
5、默认是阻塞的
6、操作管道进程结束后,自动释放
7、半双工通信
8、默认缓冲区是 4k

匿名管道进行父子进程之间通信需要用到的函数:

1int pipe(int fd[2]) 

该函数用来创建一个匿名管道,传输创建成功管道的读端和写端对应的文件描述符。

其中,fd[0] 为读端, fd[1]为写端。

通常,该函数和fork函数结合使用。

下面请看详细代码:
这段代码的意思是,通过pipe函数创建匿名管道之后。用fork函数进行子进程的创建。创建之后,在那一瞬间,父进程和子进程具有相同的文件描述符表。因此,在子进程中也存在一个文件描述符指向管道缓冲区。

因此可以进行通信。

关闭父进程的写端,关闭子进程的读端。就形成了下面的这个通信图。
在这里插入图片描述

  1 #include <stdio.h>
  2 #include <unistd.h>
  3 #include <string.h>
  4 #include <stdlib.h>
  5
  6 int main(void)
  7 {
  8     int fds[2];
  9     if(pipe(fds)==-1)
10         perror("pipe"),exit(1);
11     pid_t pid=fork();
12     if(pid==-1) perror("fork"),exit(1);
13
14     if(pid==0){//子进程
15         close(fds[0]);//关闭读端
16         sleep(1);
17         write(fds[1],"abj",3);//在写端上写入abj
18         close(fds[1]);//再关闭写端
19         exit(0);
20     }else{//父进程
21         close(fds[1]);//关闭写端
22         char buf[100]={};
23         int r=read(fds[0],buf,100);//将管道中的数据读到buf中,返回值是实际读取的字节数
24         if(r==0)//读取的自己为0,代表读取文件结束
25         printf("read EOF\n");
26         else if(r==-1){
27             perror("read"),exit(1);
28         }
29         else if(r>0)
30             printf("buf=[%s]\n",buf);
31         close(fds[0]);//读取成功,关闭读端
32         exit(0);
33     }
34 }
35

需要注意的是:
1、如果写端关闭,读端未关闭。则读端会停止阻塞,立即返回读取字节数为 0 。
因此,可在程序中根据返回的是否是 0 来判断写端是否已经关闭。
2、如果读端关闭,写端还没有关闭。那么,写端继续写,操作系统会给写端进程发送一个SIGPIPE信号,终止写端程序。

管道默认是阻塞的,那么如何设置管道为非阻塞的呢?
通过下面代码给需要修改阻塞状态的文件描述符进行增加flag的操作。

int flags = fcntl(fd[0], F_GETFL);
flags |= O_NONBLOCK;
fcntl(fd[0], F_SETFL, flags);

有名管道

有名管道与匿名管道不同的地方是:在磁盘上有这样一个文件,作为标志。
其他属性和匿名管道基本一致。

创建方式

命令的方式:mkfifo 管道名
函数的方式:int mkfifo(char* path, mode_t mode);
其中,函数方式创建,当返回值是-1的时候,表示创建失败。
其他的就类似于文件的操作了。
下面看详细代码:

写端代码:(没有进行错误判断)

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>

void main()
{
    int ret = access("/home/junkle/桌面/fifo.txt",F_OK);
    if(ret != -1) {printf("error\n");return;}
    int r = mkfifo("/home/junkle/桌面/fifo.txt", 0664);
    printf("successfully\n");
    int fd = open("/home/junkle/桌面/fifo.txt", O_WRONLY);
    char* pp = "hello world";
    while(1)
    {
        sleep(1);
        write(fd, pp, strlen(pp) + 1);
        printf("haccccccccccccc\n");
    }
    close(fd);
}

读端代码:

#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>

void main()
{
    int ret = access("/home/junkle/桌面/fifo.txt",F_OK);
    if(ret == -1) {printf("error\n");return;}
    printf("successfully\n");
    int fd = open("/home/junkle/桌面/fifo.txt", O_RDONLY);
    char pp[512] = {};
    while(1)
    {
        int num = read(fd, pp, 512);
        if(num == 0){break;}
        printf("buff = %s\n", pp);
    }
    close(fd);
    printf("finished\n");
}

可以看的出,基本和文件操作一致。
但是,管道更适合进程之间进行通信。因为其本身自带阻塞属性,文件必须等写端写入数据,读端才可以进行数据读取。

需要注意的一点是,在程序中我们尽量让写端先进行关闭,读端通过返回是否为0判断写端是否关闭了。否则,如果读端全部关闭之后,写端未关闭,操作系统会发送SIGPIPE信号给档当前进行强制关闭程序,这不是我们想要的。

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
匿名管道有名管道都是Linux系统中用于进程通信的机制,它们的主要差异在于命名方式和使用方法。 匿名管道是一种无名的管道,它只能用于在父进程和子进程之间传递数据。匿名管道只能在创建它的进程及其子进程之间使用,其他进程无法访问。匿名管道的创建使用pipe系统调用,创建后可以使用文件描述符进行读写操作。匿名管道的读写是基于先进先出的队列,数据只能单向流动。例如,以下代码演示了如何使用匿名管道在父进程和子进程之间传递数据: ``` #!/bin/bash # 创建匿名管道 pipe=$(mktemp -u) mkfifo $pipe # 在子进程中写入数据 echo "hello from child process" > $pipe # 在父进程读取数据 read line < $pipe echo "received data: $line" # 清理管道 rm $pipe ``` 有名管道也被称为FIFO管道,它是一种带有名称的管道,可以用于不同进程之间的数据传输。有名管道可以在任意进程中使用,只需要知道管道的名称即可。有名管道的创建使用mkfifo命令,创建后可以使用文件描述符进行读写操作。有名管道的读写也是基于先进先出的队列,数据只能单向流动。例如,以下代码演示了如何使用有名管道在两个进程之间传递数据: ``` #!/bin/bash # 创建有名管道 pipe=/tmp/myfifo mkfifo $pipe # 启动一个进程管道写入数据 echo "hello from process A" > $pipe & # 读取管道中的数据 read line < $pipe echo "received data: $line" # 清理管道 rm $pipe ``` 总的来说,匿名管道适用于父子进程之间的数据传输,而有名管道适用于任意进程之间的数据传输。在使用管道进行进程通信时,需要注意管道的读写顺序,否则会导致读取或写入失败。另外,管道的容量是有限的,如果写入的数据超过了管道的容量,会导致写入阻塞。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值