【通信方式一】管道
管道引入原因:
由于各个进程之间是相互独立的,这样虽然有助于程序内部自己的处理,同时也避免各个进程之间相互影响,但是有时候程序之间就是需要进行一些信息传递,这时就需要相办法来实现这些不同进程之间的通信。
管道就是为了解决这种问题应用而生的一种最基本的IPC机制。
管道基本信息
系统调用函数pipe
头文件:#include<unistd.h>
函数原型:int pipe(int filed[2]);
函数功能:调用pipe函数时在内核中开辟出一块缓冲区(称为管道)用于通信,参数为输出型参数,返回值为传出的两个文件描述符,其中filed[0]指向管道的读端,filed[1]指向管道的写端(其中0相当于标准输入,1相当于标准输出),所以管道在用户程序看起来就像一个打开的文件。调用成功返回0,调用失败返回-1
匿名管道
常见的匿名管道就是我们在Terminal上面的‘|’,之所以称为匿名管道是因为我们不能在系统的文件管理中找到相应管道所在的文件。
匿名管道的通信步骤
(1)父进程调用pipe开辟管道,得到两个文件描述符指向管道的两端;
(2)父进程调用fork创建子进程,那么子进程也有两个文件描述符指向同一管道;
(3)父子进程根据相应的需求关闭掉对应的读端或者写端;
图示举例:
匿名管道的特点:
(1)只能进行单向通信;
(2)只能用于具有血缘关系的进程,常用于父子进程之间;
(3)生命周期:随进程(因为管道的本质是文件,进程结束时文件就会关闭)
(4)管道是基于字节流的;
(5)管道内部实现同步机制,实现了数据一致性;
管道常见的四种特殊情况:
(1)有指向管道写端的文件描述符没有关闭,也没有向管道中写数据,这时有进程从管道中读数据,那么管道中的剩余数据被读取完之后会进入阻塞,直到管道中有数据可读时才读取数据并返回。
代码示例:
运行结果:
(2)指向管道读端的文件描述符没有关闭,也没有从管道中读取数据,但是有进程向管道中写数据,在管道被写满时,在写时write会阻塞,直到管道中再次有空位置才写入数据并返回。
代码示例:
(3)指向写端的进程一直在写,但是指向读端的文件描述符都关闭了,这时该进程会收到信号SIGPIPE,导致进程异常终止。
代码示例:
运行结果:
(4)所有指向管道写端的文件描述符都关闭了,读进程依然在不停的读数据,当管道中剩余的数据被读完时,就会返回0,相当于读到文件结束符。
代码示例:
运行结果:
命名管道
引入:由于匿名管只能式具有血缘关系的两个进程之间进行通信,因此引入了命名管道来实现不具有血缘关系之间的进程进行通信。
命名管道实现函数:mkfifo
函数原型:int mkfifo(const char* pathname,mode_t mode)
命名管道特点:
(1)只能进行单向通信;
(2)允许任何两个不相关进程之间进行相互通信;
(3)生命周期:随进程(因为管道的本质是文件,进程结束时文件就会关闭)
(4)管道是基于字节流的;
(5)管道内部实现同步机制,实现了数据一致性;
由于命名管道实现的是允许任何两个不相关进程进行通信,因此需要创建两个进程,一个用来发送,一个用来接收,以最简单的C/S模式为例
代码实现:(server进程用来写,client用来读)
client:
server: