管道——C

复制文件描述符

dup函数

作用

复制文件描述符

语法

#include <unistd.h>

int dup(int oldfd);

参数:所需复制的文件描述符
返回值:复制得到的文件描述符

功能:从文件描述符表中,寻找一个最小可能的文件描述符作为oldfd复制

示例1

运行结果

示例2

运行结果

在a.txt文件中打印“啦啦啦”

dup2函数

语法

#include <unistd.h>

int dup2(int oldfd,int newfd);

参数:

        oldfd:原有的文件描述符

        newfd:指定要复制到的文件描述符,如果该文件描述符已存在,则关闭原有的文件描述符

示例

运行结果

在a.txt中追加了“啦啦啦”

无名管道

概述

无名管道也叫做管道(pipe)

管道是一种特殊类型的文件,在应用层体现为两个打开的文件描述符,一个读fd[0],一个写fd[1]

口诀:0读1写

特点:

        1.管道不是普通的文件,不存在于文件系统,只存储在内存中

        2.管道是半双工的,数据在同一时刻只能向一个方向流动

                单工:数据传输只支持数据向一个方向传输

                双工:两台设备之间,允许数据的相互传输

                        全双工:允许两台设备之间同时进行相互的数据传输(如电话)

                        半双工:允许两台设备之间进行相互的数据传输,但不允许同时的数据传输,一方                  要传送数据,要等另一方传送完成后才行

        3.数据只能从管道的一端写入,只能从另一端读出

        4.写入管道中的数据遵循先入先出原则

        5.管道传输的数据是无格式的,所以读写双方要事先约定好数据的格式,如多少个字节算一个消息

        6.管道在内存中对应一个缓冲区,不同系统其大小不同

        7.从管道中读取数据是一次性的,一旦数据被取走,就会被管道抛弃,释放资源来存储其他数据

        8.管道没有名字,只能在拥有共同祖先的进程中使用

补充 :
管道可以用于任意两个或更多相关进程之间的通信,只要在创建子进程
的系列调用之前通过一个共同的祖先进程创建管道即可。
如管道可用于一个进程和其子孙进程之间的通信。第一个进程创建管
道,然后创建子进程,接着子进程再创建第一个进程的孙子进程。
管道通常用于两个兄弟进程之间的通信 —— 它们的父进程创建了管道,并
创建两个子进程。

pipe函数

概念

创建管道(无名管道)

语法

#include <unistd.h>

int pipe(fd[2]);

参数:

        fd为int型数组的首元素地址,其中fd[0]读,fd[1]写

返回值:

        成功:0

        失败:1

示例

        

运行结果

读写特点

1.用read函数从管道中读数据默认是阻塞的

2.用write函数向管道中写数据,当缓冲区已满时,write函数也会阻塞,缓冲区默认大小是64kb

3.通信过程中,当读端口全部关闭后,写进程向管道里写数据时,写进程也会退出(SIGPIPE)

4.编程时可通过fctnl函数设置文件的阻塞特性

        阻塞:fcntl(fd, FSETFL,0);

        非阻塞:fcntl(fd, FSETFL, O_NONBLOCK);

特点1

运行结果

特点2

缓冲区已满时,write也会阻塞

运行结果

从1到64

特点3

通信过程中,写端关闭,读端会解阻塞

运行结果

五秒后

特点4

通信过程中,若读端关闭,写端会收到SIGPIPE信号退出

运行结果

综合案例

使用代码实现ps -A | grep bash

运行结果

有名管道

概述

有名管道也叫命名管道

特点:

        1.半双工,数据在同一时间只能向一个方向流动

        2.写入fifo中的数据遵循先入先出原则

        3.fifo传输的数据是无格式的,所以读写双方要事先约定好数据的格式,如多少个字节算一个消息

        4.fifo在文件系统中作为一个特殊文件而存在,但fifo中的内容却存放在内存中

        5.fifo管道在内存中对应一个缓冲区,但不同操作系统的大小不一定相同

        6.从fifo中读取的数据是一次性操作,数据一旦被读取,便会被缓冲区释放,以便存储其他数据

        7.当使用fifo的进程退出后,fifo文件将继续存储在文件系统中以便后续使用

        8.fifo有名字,无血缘关系的进程可以通过打开其命名管道的方式进行通信

mkfifo函数

概念

创建有名管道

语法

#include <sys/types.h>
#include <sys/stat.h>
int mkfifo(const char *pathname, mode_t mode);
参数 :
pathname: 文件名
mode: 文件操作模式 , 一般用 0666( 所有用户可读可写 )
返回值 :
成功 :0
失败 :-1, 一般失败是因为存在与 pathname 名相同的文件

读写特点

1open打开管道 不指定O_NONBLOCK (阻塞)
1 open 以只读方式打开 FIFO 时,要阻塞到某个进程为写而打开此 FIFO
2 open 以只写方式打开 FIFO 时,要阻塞到某个进程为读而打开此 FIFO
3 open 以只读、只写方式打开 FIFO 时会阻塞,调用 read 函数从 FIFO 里读数据
read 也会阻塞。
4 、通信过程中若写进程先退出了,则调用 read 函数从 FIFO 里读数据时不阻塞;若
写进程又重新运行,则调用 read 函数从 FIFO 里读数据时又恢复阻塞。
5 、通信过程中,读进程退出后,写进程向命名管道内写数据时,写进程也会(收到
SIGPIPE 信号)退出。
6 、调用 write 函数向 FIFO 里写数据,当缓冲区已满时 write 也会阻塞。
2open打开管道 指定O_NONBLOCK (非阻塞)
1 、先以只读方式打开:如果没有进程 , 已经为写而打开一个 FIFO, 只读 open 成功,
并且 open 不阻塞。
2 、先以只写方 式打开:如果没有进程 , 已经为读而打开一个 FIFO ,只写 open 将出
错返回 -1
3 read write 读写命名管道中读数据时不阻塞。
4 、通信过程中,读进程退出后, 写进程向命名管道内写数据时,写进程也会(收到
SIGPIPE 信号)退出。
3、 注意: open 函数以可读可写方式打开 FIFO 文件时的特点:
1 open 不阻塞。
2 、调用 read 函数从 FIFO 里读数据时 read 会阻塞。
3 、调用 write 函数向 FIFO 里写数据 , 当缓冲区已满时 write 也会阻塞

示例

运行结果

进程以写的方式打开有名管道对应文件,如果此时没有进程以读的方式打开该文件,此时写的进程中的open将会阻塞

给open中移除阻塞

运行结果

1代码

2代码

1

2

1

代码1

代码2

1

2

1

综合案例

代码1

代码2

运行结果

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值