**
管道原理
**:
操作系统在内核提供的一块缓冲区(只要进程能够访问到这块缓冲区就可以实现通信)
创建管道时,操作系统会提供两个操作句柄(文件描述符),其中一个用于从管道读取数据,一个向管道写入数据
子进程通过复制父进程的方式,获取到管道的操作句柄,进而实现访问同一个管道通信
匿名管道:
内核中的缓冲区没有明确标识符,其他进程无法直接访问管道,匿名管道只能用于具有亲缘关系的进程间通信,因为匿名管道在创建的时候操作系统返回了两个句柄,因此只能通过创建子进程,子进程复制父进程的方式获取到这个管道的操作句柄,进而访问同一块缓冲区。
int pipe(int pipefd[2]);
创建一个匿名管道,向用户通过参数pipefd返回管道的操作句柄。
ipc :进程间通信
pipefd[0]:管道的读取端
pipefd[1]:管道的写入端
有两个元素的数组就是两个操作句柄
返回值:0成功 -1失败
管道的读写特性:(重要)
1)如果管道中没数据,则read会阻塞,直到读到数据(超市中买方便面没买到,会一直等)
2)管道中若数据满了,则write会阻塞,直到有空闲空间
3)若所有读端被关闭,则write会触发异常-----SIGPIPE(导致进程退出),再写的话就是浪费资源,浪费资源就是犯罪,我就要让你崩溃。
4)若所有写端被关闭,则read读完之后不会阻塞,而是返回0(告诉用户,你不要在读了,没人写了)
读出去,写进来pipe[0]用于读,pipe[1]:用于写
#进程在操作管道的时候,如果没有用到某一端,则把这一端关闭掉
管道符:| ps - ef |grep pipe(通过匿名管道实现)
shell ----父进程 ps:子进程,将处理结果打印到标准输出;标准输入重定向
grep:子进程2 循环从标准输入读取数据,标准输出重定向
命名管道:
内核中的缓冲区具有标识符(标识符是一个可见于文件系统的管道文件),其他进程可以通过这个标识符,找到这块缓冲区(通过打开同一个管道文件,访问到同一块缓冲区),进而实现通信。
int mkfifo(const char*pathname,mode_t mode):建立一个实名管道的函数(库函数)
pathname:管道文件名称
mode:文件权限
创建一个命名管道时,不会开辟一块缓冲区,因为创建管道只是创建了一个标识符,真正有进程去打开这个管道的时候,才会开辟空间,因为如果直接开辟一块内存但是一直没有进程打开的时候,就会浪费。
返回值:成功:0 失败-1
命名管道的基本使用:
命名管道可见于文件系统,会创建一个管道文件(文件只是名字),管道通信的本质还是内存中的那块缓冲区
命名管道的打开特性:
1)若管道文件以只读的方式打开,则会阻塞,直到这个管道文件被以写的方式打开
2)若管道文件以只写的方式打开,则会阻塞,直到这个管道文件被以读的方式打开
3)若管道以读写方式打开,则不会阻塞。
总结:
匿名管道只能用于具有亲缘关系的进程间通信,命名管道用于任意的进程间通信
管道的生命周期随进程
管道提供流服务—字节流传输:数据放在缓冲区中(有序、连接、可靠,传输比较灵活)
优点:传输灵活
缺点:数据粘连(数据在缓冲区中堆积在一起了)
管道自带同步与互斥功能(读写操作和数据大小不超过PIPE_BUF大小,读写操作受保护)
互斥:对临界(公共)资源同一时间的唯一访问性(我操作时别人不能操作),对管道进行数据操作的大小不超过PIPE_BUF=4096的时候,则保证操作的原子性。
同步:对临界资源的时序可控性(我操作完了别人才能操作),避免一个人一直在操作,其他人操作不了
“互斥保证安全,同步保证合理”
管道的生命周期随进程
字节流传输就好像水流一样,而数据报传输就好像冰块一样,如果冰块太她了,就会出现传送不了的情况。
ps -ef | grep ssh这个原理?
在创建ps -ef和grep ssh这两个进程之前,创建一个管道。
ps -ef命令的默认功能,将结果写入到标准输出
grep ssh 一直从标准输入读取数据进行过滤
管道的同步与互斥体现就是:
管道没有数据则被阻塞,放了数据之后,唤醒对方阻塞,对方读数据(我放了,你才能读–同步),数据往管道中没放完别人不能读也不能写