由于进程之间的独立性,要让两个毫无关联的进程通信,需要先解决的问题就是让不同进程看到同一份资源(内存文件、内存、队列)。
匿名管道是通过“子进程会继承父进程的资源”这一特性实现父子进程的通信,这样的话父子进程就能看到同一份资源(不需要名字来标识同一个资源,所以叫匿名管道)
命名管道是通过 路径+文件名 看到同一份资源。最典型的就是像下面这样,在知道路径以后,一个进程先向磁盘文件写入数据,另一个进程再从这个磁盘文件读取数据,但是这样的读写效率比较低。
下面就按照这个思路来了解命名管道的是如何充当两个进程的桥梁的
目录
一、命名管道的作用方式
一个文件可以被多个进程打开,最典型的就是我们的stdout 。文件被打开以后,就会被加载到内存中,我们让进程A 以只写的方式打开,进程A写入时,不让数据刷新到磁盘;进程B以只读的方式打开
然后进程A向这块内存中写入数据,进程B从这块内存中读取数据,这样就实现了毫无关联的进程之间的基本通信。和匿名管道一样,命名管道的通信是单向的,要么只读,要么只写,所以在打开管道文件的时候,无法以读/写的方式打开管道文件。
二、命名管道创建函数mkfifo
mkfifo被调用的以后,会创建一个管道文件(管道的本质就是文件),等同于上面图中的磁盘文件
第一个参数:表示管道文件的创建路径,即要在哪创建这个文件
第二个参数:表示管道文件的初始权限,一般文件被创建的时候,权限包含可读/可写/可执行
返回值:管道创建成功时,返回0;否则返回 -1
三、管道文件创建和使用
下面我们就要试着通过管道让两个进程来通信,一个进程是服务端,一个进程是客户端。服务端负责读取,客户端负责写入。注意不要以O_RDWR的方式打开管道文件,管道通信是单向的,要么只读,要么只写。
1、在服务端进程中创建管道
一般来说,服务端创建了管道,那么客户端就直接可以用服务端创建好的管道进行通信了
这里可以写个Makefile测试一下是否能创建成功
Makefile的内容及测试结果如下,如果有下面这样的管道文件,那就说明创建成功了
2、 服务端从管道读取数据
创建好管道文件以后,服务端就可以打开文件,然后从里面读取数据了
注意:
客户端因为要向管道文件写入数据,客户端如果关闭了文件,服务端这边就无法读取到数据,即读取到的文件字节数bytes = 0,此时就没有必要继续读了,所以需要在while循环外加一个close(fd)
3、 客户端向管道内写入数据
管道创建好以后,即磁盘文件有了,一个进程(客户端端)以只写的方式打开文件,然后向这个文件中写入数据
但是客户端要如何获取到管道路径呢??我们可以把刚才服务端中管道路径的宏定义移动到一个头文件common.h里,同时让客户端和服务端包含这个头文件
======================== common.h ========================
因为read函数和write函数都要用到下面这些头文件,所以我们下面这些头文件都放到common.h中,然后让server.c 和 client.c都包含common.h
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h> //close函数
======================== server.c ========================
======================== client.c ========================
我们先从键盘读取内容,然后将读取到的内容写入管道文件,具体操作步骤如下图