IO进程间通信-无名管道、有名管道

1.无名管道

1.1特点

(1)只能用于具有亲缘关系的进程之间的通信

(2)半双工的通信模式,具有固定的读端fd[0]和写端fd[1].

(3)管道可以看成是一种特殊的文件,对于他的读写可以使用文件IO,如read,write。

(4)管道是基于文件描述符的通信方式。当一个管道建立时,他会创建两个描述符fd[0],fd[1],其中fd[0]固定用于读管道,而fd[1]固定用于写管道。

1.2函数接口

int pipe( int fd[2])

功能:创建无名管道

参数:文件描述符 fd[0]:读端 fd[1]:写端

返回值:成功 0

                失败 -1

#include <unistd.h>
#include <stdio.h>

int main(int argc, char const *argv[])
{
    // fd[0] 代表读端 ,fd[1]代表写端
    int fd[2] = {0};

    char buf[65536] = "";
    // 创建无名管道
    int n = pipe(fd);
    // 判断无名管道是否创建成功
    // 若成功,返回值为0;失败,返回值为 -1
    if (n < 0)
    {
        perror(" pipe error");
        return -1;
    }
    // 查看管道读写端的文件描述符
    printf("fd[0]:%d fd[1]:%d \n", fd[0], fd[1]);
    // 通过fd[1]端向管道中写
    write(fd[1], "hello world", 11);
    // 通过fd[0]端从管道中读
    read(fd[0], buf, 11);
    printf("%s \n", buf);

    return 0;
}

1.3注意事项

(1)当管道中无数据,读操作会阻塞。

        当管道中有数据,关闭写端,可以将数据读出

        当管道中无数据,关闭写端,读操作会立即返回

(2)管道中写满(管道大小64k)再写数据会阻塞,只有用大于4k空间之后,才可以继续写数据

(3)只有当管道读端存在时,向管道中写数据才有意义,否则会导致管道破裂。向管道中写入数据昵称会收到来自内核的SIGPIPE信号(通常是broke pipe 错误)。

2.有名管道

2.1特点

(1)有名管道可以使互不相关的两个进程互相通信
(2)有名管道可以通过路径名来指出,并且在文件系统中可见,但内容存放在内存中,但是读写数据不会在文件中,而是在管道中。

(3)进程通过文件IO来操作有名管道

(4)有名管道遵循先进先出原则

(5)不支持如lseek()操作

2.2函数接口

int mkfifo( constchar *filename, mode_t mode);

功能:创健有名管道

参数:filename:有名管道文件名

        mode:权限

返回值:成功:0

        失败:-1,并设置errno号

注意对错误的处理方式:

如果错误是file exist时,注意加判断,如:if(errno == EEXIST)

注:函数只是在路径下创建管道文件,往管道中写的数据依然写在内核空间。

先创建有名管道,然后用文件IO操作:打开、读写和关闭。

2.3注意事项

(1)只写方式打开,阻塞,一直到另一个进程把读打开

(2)只读方式打开,阻塞,一直到另一个进程把写打开

(3)可读可写,如果管道中没有数据,读阻塞。

// 1. `O_RDONLY`:只写方式打开阻塞。这表示该文件描述符以只读方式被打开,
// 如果尝试写入数据到该管道,会一直阻塞,直到另一个进程使用写方式打开该管道。

// 2. `O_WRONLY`:只读方式打开阻塞。这表示该文件描述符以只写方式被打开,
// 如果尝试从该管道读取数据,会一直阻塞,直到另一个进程使用读方式打开该管道。

// 3. `O_RDWR`:可读可写。
// 如果管道中没有数据可读,读取操作会阻塞,直到有数据可读;
// 如果管道已满,写入操作也会阻塞,直到有足够的空间可写。

2.4读写示例

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

int main(int argc, char const *argv[])
{
    int fd;
    char buf[32] = "";

    // 创建管道文件
    int n;
    n = mkfifo("fifo", 0666);
    // 判断管道文件是否创建成功
    if (n < 0)
    {
        // 如果错误号errno为EEXIST则代表管道文件已存在
        // 如果管道文件已存在,则打印句提示语句而不是走到return -1
        if (errno == EEXIST)
        {
            printf("file exist\n");
        }
        else
        {
            perror("mkfifo err");
            return -1;
        }
    }
    printf("mkfifo success\n");

    // 打开管道文件
    fd = open("fifo", O_RDWR);

    if (fd < 0)
    {
        perror("fifo open error");
        return -1;
    }
    printf("fd = %d \n", fd);

    // 读写操作
    write(fd, "hello", 5);
    read(fd, buf, 32);
    printf("%s \n", buf);

    return 0;
}

3.无名管道和有名管道的区别

无名管道

有名管道

使用场景

只能用于具有亲缘关系的进程之间的通信

不相干的两个进程也可以

特点

半双工的通信模式

具有固定的读端fd[0]和写端fd[1]。

通过文件IO操作

管道是基于文件描述符的通信方式。

在文件系统中会存在管道文件,但是数据放在内核空间

通过文件IO进行操作

遵循先进先出,不支持lseek操作

函数

pipe()

直接read、write

mkfifo()

先打开open,再读写read、write

读写特性

管道中无数据,读阻塞

关闭写端,有数据读出,无数据立即返回

管道写满64k,写阻塞,直到有4k空间才能继续写入

关闭读端,写入会使管道破裂

只写方式打开会阻塞,一直到另一个进程把读方式打开

只读方式打开会苏俄,一直到另一个进程把写方式打开

可读可写,如果管道中无数据读会阻塞

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值