进程间通信 - 通道
进程间通信 - 通道
什么是管道?
进程间的通信方式有五种,分别为:管道、信号量、共享内存、消息队列和套接字。
管道:本质上就是一个文件,前面的进程以写方式打开文件,后面的进程以读方式打开。这样前面写完后面读,于是就实现了通信。即把一个进程的输出直接连接在另外一个进程的输入。
虽然实现形态上是一个特殊文件,对管道的读写可以使用普通的read(),write()函数,但管道不属于任何文件系统(管道本身并不占用磁盘或者其他外部存储的空间)。
在Linux的实现上,它占用的是内存空间,只存在于内存中。所以,Linux上的管道就是一个操作方式为文件的内存缓冲区。即管道本质上是内核的一块缓存。
管道分为有名管道和无名管道两种,它们的区别是:
- 无名管道:又称为匿名管道(Anonymous Pipe),只能在亲缘进程(是指有同一个祖先如父子进程、兄弟进程)之间进行通信。
- 有名管道:又称为命名管道(Named Pipe),可以在任意两个进程之间进行通信。
管道通信模式
通信模式分为:
- 单工:数据只在一个方向上传输,不能实现双方通信
- 半双工(切换的单工):允许数据在两个方向上传输,但是同一时间数据只能在同一个方向上传输
- 全双工:允许数据在两个方向上同时传输
管道是半双工的,数据只能向一个方向流动;需要双方通信时,需要建立起两个管道,
管道的特点
- 管道是半双工的
- 管道提供流式服务,字节流通信,没有消息边界,多个进程同时发送的字节流混在一起,则无法分辨消息,所有管道一般用于两个进程之间通信。
- 管道的内容读完后不会保存
- 一般而言,进程退出,管道释放,所以管道的生命周期跟随进程
- 一般而言,内核会对管道操作进行同步与互斥
- 匿名管道一般用于亲缘进程间通信,命名管道一般用于两个无关联进程间通信
匿名通道(PIPE)
是一种亲缘进程间的通信方法。匿名管道存在于kernel(内核)中,A,B必须具有亲缘关系进程。同一时刻,只能有一个写端或一个读端。
父子进程间,只要是**fork()**出来的,就会完美复制父进程的数据。如果在fork0)之前创建管道,并获取管道的操作接口,子进程就能使用管道。
命名管道(FIFO)
**命名管道(Named Pipe)**是一种独立进程之间通信的机制,用于在无关的进程之间进行数据传输。
与匿名管道不同,命名管道不需要亲缘关系的进程之间,也不需要共享同一终端。任意进程可以通过打开命名管道的读取端和写入端来与其进行通信。
命名管道通过在文件系统中创建一个特殊的文件来实现通信。这个特殊的文件被称为FIFO(First-inFirst-out)或命名管道。
命名管道通信的原理:
- 和匿名管道一样,想让双方通信,必须先让双方看到同一份资源!它和匿名管道本质是一样的,只是看到资源的方式不同。
- 匿名管道是通过父子进程继承来看到同一份资源的,也叫做管道文件,这个文件是纯内存级的,所以没有名字,叫做匿名管道。
- 而命名管道是在磁盘上有一个特殊的文件,这个文件可以被打开,但是打开后不会将内存中的数据刷新到磁盘。在磁盘上就有了路径,而路径是唯一的,所以双方就可以通过文件的路径 来看到同一份资源,即管道文件。
命名管道的特点:
- 命名管道可以使互不相关的两个独立进程实现彼此通信
- 命名管道可以通过路径名来指出,并且在文件系统中是可见的。在建立管道之后,两进程就可以把它当作普通文件进行读写,使用非常方便。
- FIFO严格遵循先进先出原则,对管道及FIFO的读总是从开始处返回数据,对它们的写则把数据添加到末尾。命名管道不支持如Iseek0)等文件的定位操作。
- 命名管道依然在内核态内存中
- 命名管道在文件系统中有节点(即在文件系统中可以找到)
- 命名管道严格遵循先进先出原则
- 命名管道不能使用文件重定位的函数lseek()
- 命名管道可以用在亲缘和非亲缘进程间(一般用于非亲缘进程间通信)
管道命名
在Linux shell中执行命令,经常会将上一个命令的输出作为下一个命令的输入,由多个命令配合完成一件事情。而这就是通过管道来实现的。|这个竖线就是管道符号。
Is-llgrep string //grep是抓取指令
●1s命令(其实也是一个进程)会把当前目录中的文件都列出来但它不会直接输出,而是把要输出到屏幕上的数据通过管道输出到grep这个进程中,作为grep这个进程的输入;
●然后这个进程对输入的信息进行筛选(grep的作用),把存在string的信息的字符串(以行为单位)打印在屏幕上。