Linux系统编程11_管道和命名管道

时间:2021-04-13 11:51:05   收藏:0   阅读:0

=======================【管道】=====================
https://www.cnblogs.com/sparkdev/p/10997135.html

管道(pipe)是进程间通信的一种实现方式。
在 Linux 系统中,管道本质上是一种特殊的文件,它的主要用途是实现进程间的通信。    

管道的一个显著特点是:创建一个管道后,会获得两个文件描述符,分别用于对管道进行读取和写入操作。
通常将这两个文件描述符称为管道的读取端和写入端,从写入端写入管道的任何数据都可以从读取端读取。


对一个进程来说,管道的写入和读取操作与写入和读取一个普通文件没有什么区别,只是在内核中通过这种机制来实现进程间的通信而已。


#include <unistd.h>
int pipe(int filedescriptors[2]);
pipe 函数相对来说是一个比较底层的函数,它创建一个管道(相对于命名管道而言,这个管道又被称为匿名管道)。
参数 filedescriptors 是一个长度为 2 的整型数组,用于存放调用该函数所创建管道的文件描述符。
其中 filedescriptors[0] 存放管道读取端的文件描述符,filedescriptors[1] 存放管道写入端的文件描述符。
调用成功时,返回值为 0;调用失败时,返回值为 -1。

管道本身是一个抽象的概念,其本质是通过对特殊文件的读写实现进程间的通信。
一个管道实际上就是个只存在于内存中的文件,对这个文件的操作要通过两个文件描述符进行,它们分别代表管道的两端。
因此管道是一种特殊的文件,它不属于某一种文件系统,而是一种独立的文件系统,有其自己的数据结构。

调用 pipe 函数创建了一个管道后,还不能实现通过管道在两个进程间通信的目的,因为此时管道的读取端和写入端的文件描述符都属于同一个进程。
我们知道,在 Linux 系统中,通过 fork 系统调用创建子进程时,父进程中打开的文件描述符仍将保持打开状态。

所以,常见的做法是:先在父进程中创建管道,然后通过 fork 调用创建子进程,这时就可以通过管道在父子进程间传递数据了。
实际的使用中,常常在子进程中调用 exec 族函数执行特定的程序,然后根据数据传输的方向分别关闭父进程和子进程中的一个文件描述符(注意,此时只能单向传输数据。
如果要双向传输数据,最好是创建两个单向传输的管道)。
例如:要实现父进程向子进程传输数据,则关闭父进程中的读取端(filedescriptors[0])文件描述符和子进程中的写入端文件描述符(filedescriptors[1])。

由于管道是一种特殊的文件,用户在使用中完全可以像读写普通文件一样对管道进行读写,所使用的函数为 read 和 write。
系统定义的常数 PIPE_BUF 规定了管道缓冲区的大小,当写入数据超过规定的大小时,就会发生数据错乱。
虽然管道是一种特殊的文件,它的读写操作和普通文件的读写操作也完全相同,但管道不是一个真实存在的文件,它只在内核中存储,而不存在于文件系统中。

管道虽然被广泛使用,但是也有其局限性。管道的最大特点就是要求进程之间具有同源性,即它们必须是最终由同一个进程所派生的进程。当然这个缺点可以通过命名管道解决。
管道的另一个缺点是半双工的工作方式,即只允许单向传输数据。这一点管道和命名管道是相同的,可以创建两个单向管道来实现数据的双向传输。

================【命名管道】=====================
命名管道(named pipe)又被称为先进先出队列(FIFO),是一种特殊的管道,存在于文件系统中。

命名管道与管道非常类似,但是又有自身的显著特征:


命名管道可以用于任何两个进程间的通信,而不限于同源的两个进程。
命名管道作为一种特殊的文件存放在文件系统中,而不是像管道那样存放在内核中。


当进程对命名管道的使用结束后,命名管道依然存在于文件系统中,除非对其进行删除操作,否则该命名管道不会自行消失。


和管道一样,命名管道也只能用于数据的单向传输,如果要用命名管道实现两个进程间数据的双向传输,建议使用两个单向的命名管道


创建命名管道:
1)命令行上创建命名管道:
    mkfifo /tmp/testp
    mknod  /tmp/testp p
可以通过 ls 命令查看命名管道的文件属性
输出中的第一个字符为 p,表示这个文件的类型为管道。最后的 | 符号是有 ls 命令的 -F 选项添加的,也表示这个一个管道。

2)在程序中创建命名管道:
可以使用 mkfifo 函数
#include <sys/types.h>
#include <sys/stat.h>
int mkfifo(const char *pathname, mode_t mode);
参数 pathname 是一个字符串指针,用于存放命名管道的文件路径。参数 mode 用于表示指定所创建文件的权限。该函数调用成功时返回 0;调用失败时返回 -1。

mkfifo 函数是一个专门用来创建命名管道的函数,而另外一个函数 mknod 却可以兼职创建命名文件
int mknod(char *pathname, mode_t mode, dev_t dev);
创建命名管道只是 mknod 函数的功能之一,它的前两个参数和 mkfifo 函数相同。在创建命名管道时,为第三个参数 dev 传递 0 就可以了。
该函数调用成功时返回 0;调用失败时返回 -1。

删除命名管道
删除命名管道和删除一个普通文件没有什么区别。

评论(0
© 2014 mamicode.com 版权所有 京ICP备13008772号-2  联系我们:gaon5@hotmail.com
迷上了代码!