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空间才能继续写入

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

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

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

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值