pipe和fifo

简介

pipe称之为无名管道fifofirst in first out的缩写,称之为有名管道

pipe是最初的进程间通信IPC形式,但是由于他没有名字,所以只能局限于有亲缘关系的进程间使用(父子进程)。之后引入了fifo,就解决了这个问题。

历史上的pipe通常是指半双工管道,只允许数据单向流动。现代系统大都提供全双工管道,数据可以沿着管道双向流动。

fifo是半双工的

pipe

原型

fd[2]为两个文件描述符:fd[0]fd[1],前者打开负责读,后者打开负责写。

1、单进程内单向数据流

2、父子进程间的数据流
尽管管道是有单个进程创建的,却很少在单个进程内使用,下图将展示父子进程间的管道通信。

3、父子进程间的单向数据流
如果说父进程关闭读,子进程关闭写,那么父子进程就提供了一个单向数据流。如下图

4、*nix系统shell管道数据流

假设命令为:

fifo

原型

pathname是一个普通的路径名称,它是这个fifo的名字。
mode是指文件的权限位

fifo的模型大致与pipe类似,它的真正优势表现在服务端可以长期运行一个进程,与客户端无亲缘关系。建立一个经典的C/S架构

客户端将自己的pid告诉服务端,服务端可以通过组合找到客户端fifo名称,然后继续传出信息。

fifo需要注意一下几点

1、 fifo的写操作是原子性的,也就是说2个客户端发送消息,不会混乱在一起。
2、 fifo不支持nfs文件系统。fifo只能在单台主机上使用的IPC形式。
3、 当2个客户端几乎同时向服务端发送请求,第一台发送10M数据,需要10秒,第二台发送10字节,只需要1秒,那么第二台必须等待第一台完成发送后才能被处理。这种形式叫做迭代服务端。可以将其改造为并发服务端来解决这个问题。最常见的方式是,服务端为每一个发送数据的客户端fork一个子进程来接收数据。
4、 fifo的容量是有限的,为64K,并且不能修改。

php实现

代码已经上传到packagist.org

只需要composer require pangou/fifo 下来就可以了。

主要为2点:
1、 createFifo方法主要思路:
1) 判断fifo文件是否存在,类型是否为fifo,不是这备份后删除
2) 判断fifo文件是否存在,不存在则创建,创建失败抛异常
3) 判断文件类型是否为fifo,不是抛异常
2、 *nix系统一切皆文件的观点,所以fifo也是以文件读取写入的方式进行交互。

案例一、 单进程交互

需要注意的是read方法必须传入正好能够接收消息的长度。过长则进程进入阻塞状态,无数据写入的话永远阻塞着了。过短则,无法接受完整数据。

案例二、父子进程交互

非亲缘关系进程交互与父子进程交互类似,只是分为2个文件执行而已。

传输协议

上面2个示例中可以看到,接收数据方,必须传入节后数据大小才可以接收完成数据。但是真实环境中怎么可能知道需要接收多少字节?

这里引入了数据长度传输协议,消息体前N个字节为消息长度,那么就可以完美解决这个问题了。

重新改造fifo

使用方式

压测

曾经也做过一篇关于共享内存文件MemcacheCache的压测, 天然的memcache —— /dev/shm

由于管道也是存在于内核中的所以性能还算不错,10W次读写0.4秒左右。是/dev/shm性能的双倍。当然这个使用场景不一样,完全没有可比性 : ) 。