管道是在本机上进程间通信
如果不用今天学的管道进行进程间通信
使用file.txt,a把数据写到文件中,b从文件中把数据读出来
存在的问题:读的程序不知道写的程序何时写入数据,而且磁盘的读写速度相当于内存来说是非常慢,差的数量级的慢
这个方式:这个file.txt在磁盘上存放,访问速度非常慢
磁盘慢,内存快一些,缓存更快,寄存器更更快,但是小
对于管道文件,打开以后,是在内存中创建一个空间!!!
管道可以用来在两个进程之间传递数据,如: ps -ef | grep “bash”, 其中‘|’就是管道,其作用就是将 ps 命令的结果写入管道文件,然后 grep 再从管道文件中读出该数据进行过滤。
有名管道
也叫做命名管道,在2个不相关的进程之间进行通信,通过open打开同一个管道文件进行读写通信,也可以用于父子进程间的通信
管道也是文件,linux系统上一切皆文件,打开管道,得到的也是文件描述符,所以可以进行读和写
mkfifo既是一个命令,同时也有一个和它同名的系统调用,可以在程序中直接使用
有名管道可以在任意两个进程之间通信,而且是在内存中写入数据
另外一个进程也是从内存读取数据,内存中读取数据效率很高哦!
有名管道的创建:
命令创建: mkfifo FIFO
系统调用创建
#include <sys/types.h>
#include <sys/stat.h>
//filename 是管道名 mode 是创建的文件访问权限
int mkfifo(const char *filename, mode_t mode);
下面是命令创建有名管道,取名fifo
ls -l查看
这里的p就是管道类型的文件
必须有一个读端和一个写端,才可以进行通信
两个进程要同时打开
否则就阻塞,不让打开
open write read close
虽然可以看到这个管道文件
但是这个管道文件大小永远为0
因为是不会把数据写到磁盘上的,都是在内存上,所以大小是0
管道只有只读和只写这2种打开方式,没有读写方式!!!
编写a.c
( 只写方式打开)
编写b.c
(只读方式)
gcc -o a a.c
dcc -o b b.c
./b
在另外一个终端的相同位置:./a
对方如果关闭管道,直接返回
以read==0作为判断对方关闭管道的条件,因为如果对方管道是开的,是因为没有发数据,read方法是会阻塞住的,对方关闭管道,read返回值为0
循环写入读取需要这个条件
vi a.c
vi b.c
在两个终端分别运行这两个程序
不能向关闭的管道写数据,这样是有问题的,被对方关闭了,也不能去写
允许多个读和写
改成一次只读一个字节
我们打开管道后,会给内存分配空间,划分一个字节一个字节
头指针和尾指针控制
写入数据,头指针往后移动
读取数据,尾指针往后移动
类似于顺序循环队列
写满了。write会阻塞
空的话,read会阻塞
管道的特点
1、无论有名还是无名,写入管道的数据都在内存中
2、管道是一种半双工通信方式(通信方式有单工、半双工、全双工)
3、有名和无名管道的区别:有名可以在任意进程间使用,而无名主要在父子进程间
Ctrl+c,进程结束,所有打开的文件描述符自动关闭把a关闭,写端关闭,b读端返回值为0,正常退出
如果把b关闭,读端关闭,a写入数据就退出了,往关闭的管道写数据,没人读,内核认为产生异常,发送信号,通知结束进程
在写端加上信号函数
如果又有读端了
无名管道
无名管道主要应用于父子进程间的通信,使用起来方便简单
是把文件描述符通过fork方式带到子进程中的
无名管道的创建:
pipe会向fds数组填充值
图解如下:
运行后如下
打印fd[0],fd[1]
为什么是3,4
其实就是文件表的下标值
管道通信是半双工的,不能同时从父到子,子到父同时读写。
我们使用管道通信,一般来说数据流是单向的