Linux中IPC机制:管道和FIFO

来源:互联网 发布:委内瑞拉中国布局知乎 编辑:程序博客网 时间:2024/05/17 03:37

前言

这一周来过的很浮躁,感觉什么也没干,时间就这么过去了。实习工作需要看协议,看的头昏脑胀,晚上还得写论文。Nginx基本没时间碰,略吐槽下。。白天工作时间趁着看别人修改的协议代码机会,顺便复习下代码中用到的管道机制,简单记录下。另外,顺利入手第一台单反,我大尼康D7000~

管道

管道是最早类型的IPC形式了,所有Unix类系统都提供管道机制。它由pipe函数提供单路(单向)数据流。原型如下:
int pipe(int fd[2]);
该函数返回两个文件描述符:fd[0]和fd[1]。前者用来读,后者用来写。
这种方式属于半双工管道,常用于shell中创建一个全双工IPC管道可以使用socketpair函数实现

通常,管道由单个进程创建,却很少在单进程内使用。管道的典型用途是用于父子进程间的通信。由一个进程(将成为父进程)创建一个管道后调用fork派生一个子进程,具体如下图:


接着,父进程关闭管道的读出端,子进程关闭写入端,即完成单向数据管道,如下图:


当需要双向数据流时,我们可创建两个管道,每个方向一个即可。如下图:

FIFO

管道的最大劣势是只能用于有一个共同祖先进程的各个进程之间。在无亲缘关系的两个进程间创建一个管道并用于IPC是不行的。FIFO就是指先进先出,也就是有名管道(named pipe)。它不同于管道的是,每个FIFO均与一个路径名关联,从而允许无亲缘关系的进程可以同时访问一个FIFO
原型如下:
int mkfifo(const char *pathname, mode_t mode);
mode参数类似与open()的第二个参数。
mkfifo函数已隐含指定O_CREAT | O_WXCL。它要么创建一个新的FIFO,要么返回错误。如果要打开一个已存在的FIFO或创建一个新的FIFO,应先调用mkfifo,再检查其是否返回错误,若返回错误,应该改为调用open()。可以从shell脚本或命令行中使用mkfifo命令。具体请参考《网络编程卷二》

管道和FIFO额外属性


笔记:对一个描述符设置非阻塞的两种方法
  1. 调用open()函数时指定O_NONBLOCK标志;
  2. 描述符已被打开,调用fcntl()以启用O_NONBLOCK标志;
关于管道和FIFO的读出与写入的额外规则:
  • 1,如果请求读出的数据量多于管道或FIFO中当前可用数量,那么只返回可用的数量;
  • 2,如果请求写入的数据的字节数小于或等于管道的缓存大小,那么write操作能保证是原子操作。也就是说,系统不会相互混杂两个进程的数据,必须等一个进程写完所有数据,另一个进程才能开始写重要);否则,不能保证;
  • 3,O_NONBLOCK标志的设置对write操作的原子性无影响,原子性完全由所请求字节数小于等于管道缓存大小决定;但如果管道或FIFO被设置非阻塞,write的返回值会取决于待写字节数以及该管道或FIFO中当前可用空间的大小。
当待写字节数小于等于缓存大小时,有以下情况:
  • a)管道空间足够,全部写入;
  • b)管道空间不足,立即返回错误;
当待写字节数大于缓存大小时,有以下情况:
  • a)管道空间至少有1字节空间,有多少写入多少,write返回实际写入值;
  • b)管道已满,立即返回错误;
  • 4,如果为一个没有为读打开的管道或FIFO写入,内核产生SIFPIPE信号;

管道和FIFO限制

系统加于管道和FIFO的唯一限制:
  • OPEN_MAX: 一个进程在任意时刻能打开的最大描述符;(通过sysconf命令查询);
  • PIPE_BUF:管道缓存大小,可原子性写往一个管道或FIFO的最大数据量;

总结

管道机制最重要的一个优点就是当写入数据量小于等于管道缓存大小时,能够保证原子性的操作

主要参考

《网络编程卷二》
0 0
原创粉丝点击