在Linux / Unix系统中,什么是命名管道或FIFO?

管道用于在相关过程之间进行通信。我们不能使用管道进行不相关的过程通信。然后,为了实现不相关的进程通信,简单的答案是命名管道。即使这适用于相关流程,也不能将命名管道用于相关流程通信。

与管道不同,我们可以使用单个命名管道,该管道可以用于双向通信(服务器和客户端之间的通信,以及客户端和服务器之间的通信),因为命名管道支持双向通信。

命名管道的另一个名称是FIFO(先进先出)。让我们看看系统调用(mknod())创建一个命名管道,这是一种特殊文件。

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
int mknod(const char *pathname, mode_t mode, dev_t dev);

该系统调用将创建一个特殊的文件或文件系统节点,例如普通文件,设备文件或FIFO。系统调用的参数是路径名,模式和dev。路径名以及模式和设备信息的属性。路径名是相对的,如果未指定目录,它将在当前目录中创建。指定的模式是文件模式,它指定文件类型,例如文件类型和下表中提到的文件模式。dev字段用于指定设备信息,例如主要和次要设备编号。

文件类型描述文件类型描述
S_IFBLK阻止特殊S_IFREG常规文件
S_IFCHR特殊字符S_IFDIR目录
S_IFIFOFIFO特殊S_IFLNK符号链接


文件模式描述文件模式描述
S_IRWXU
由所有者读取,写入,执行/搜索
工作组
写权限,组
S_IRUSR
阅读权限,猫头鹰
S_IXGRP
执行/搜索权限,组
S_IWUSR
写许可,所有者
S_IRWXO
执行/搜索权限,组
S_IXUSR
执行/搜索权限,所有者
S_IROTH
阅读权限,其他
S_IRWXG
按组读取,写入,执行/搜索
S_IWOTH
写许可,其他
S_IRGRP
阅读权限,组
S_IXOTH
执行/搜索权限,其他

文件模式也可以用八进制表示法表示,例如0XYZ,其中X表示所有者,Y表示组,Z表示其他。X,Y或Z的值可以在0到7之间。读,写和执行的值分别为4、2、1。如果需要结合读,写和执行,则相应地添加值。

说,如果是0640,则意味着对所有者进行读写(4 + 2 = 6),对组进行读取(4),对其他用户则没有权限。

成功时此调用将返回零,失败时将返回-1。要知道失败的原因,请检查errno变量或perror()函数。

#include <sys/types.h>
#include <sys/stat.h>
int mkfifo(const char *pathname, mode_t mode)

该库函数创建一个FIFO特殊文件,该文件用于命名管道。此函数的参数是文件名和模式。文件名可以是绝对路径,也可以是相对路径。如果未提供完整路径名(或绝对路径),则将在执行进程的当前文件夹中创建文件。文件模式信息如mknod()系统调用中 。

成功时此调用将返回零,失败时将返回-1。要知道失败的原因,请检查errno变量或perror()函数。

让我们考虑一个程序,该程序在一个终端上运行服务器,而在另一终端上运行客户端。该程序将仅执行单向通信。客户端接受用户输入并将消息发送到服务器,服务器将消息打印在输出上。继续该过程,直到用户输入字符串“ end”。

让我们通过一个例子来理解这一点-

步骤1-创建两个进程,一个是fifoserver,另一个是fifoclient。

步骤2-服务器进程执行以下操作-

  • mknod()如果未创建,则使用名称“ MYFIFO”创建一个命名管道(使用系统调用)。

  • 打开命名管道以用于只读目的。

  • 在这里,创建了具有所有者读写权限的FIFO。阅读“组”信息,没有“其他”权限。

  • 无限等待来自客户端的消息。

  • 如果从客户端收到的消息不是“结束”,则打印该消息。如果消息是“结束”,则关闭FIFO并结束该过程。

步骤3- 客户端进程执行以下操作-

  • 1)打开命名管道仅用于写目的。

  • 2)接受来自用户的字符串。

  • 3)检查用户是否输入“结束”或“结束”以外的其他内容。无论哪种方式,它都会向服务器发送一条消息。但是,如果字符串为“ end”,则这将关闭FIFO并结束该过程。

  • 4)无限重复,直到用户输入字符串“ end”。

使用命名管道的双向通讯

管道之间的通信是单向的。通常,管道仅限于单向通信,并且至少需要两条管道进行双向通信。管道仅用于相互关联的过程。管道不能用于不相关的进程通信,例如,如果我们要从一个终端执行一个进程,并从另一个终端执行另一个进程,则无法使用管道。命名管道用于两个或多个不相关进程之间的通信,也可以具有双向通信。

我们已经看到了命名管道之间的单向通信,即从客户端到服务器的消息。现在,让我们看一下双向通信,即客户端使用相同的命名管道将消息发送到服务器,而服务器接收消息,然后将另一条消息发送回客户端。

以下是一个例子-

步骤1-创建两个进程,一个是fifoserver_twoway,另一个是fifoclient_twoway。

步骤2- 服务器进程执行以下操作-

  • mkfifo()如果未创建,则在/ tmp目录中使用名称“ fifo_twoway”创建一个命名管道(使用库函数)。

  • 打开命名管道以进行读写。

  • 在这里,创建了具有所有者读写权限的FIFO。阅读“组”信息,没有“其他”权限。

  • 无限等待来自客户端的消息。

  • 如果从客户端收到的消息不是“ end”,则打印该消息并反转字符串。反向的字符串将发送回客户端。如果消息是“结束”,则关闭FIFO并结束该过程。

步骤3-客户端进程执行以下操作-

  • 打开命名管道以进行读写。

  • 接受来自用户的字符串。

  • 检查用户输入的是“结束”还是“结束”以外的内容。无论哪种方式,它都会向服务器发送一条消息。但是,如果字符串为“ end”,则这将关闭FIFO并结束该过程。

  • 如果消息发送不是“结束”,它将等待来自客户端的消息(反向字符串)并打印反向字符串。

  • 无限重复,直到用户输入字符串“ end”。