我们使用一根管道进行单向通信,而使用两条管道进行双向通信。同样的条件适用于命名管道,因为命名管道支持双向通信,所以我们可以使用可用于双向通信(服务器和客户端之间的通信,以及客户端和服务器之间的通信)的单个命名管道。

命名管道的另一个名称是 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);

该系统调用将创建一个特殊的文件或文件系统节点,如普通文件,设备文件。系统调用的参数是路径名(pathname),模式(mode)和dev。

pathname  -  路径名以及模式和设备信息的属性,路径名是相对的,如果未指定目录,它将在当前目录中创建。

mode         -  指定的模式是文件模式,它指定文件类型,如文件类型和下表中提到的文件模式。 

dev            -  字段用于指定设备信息,如主要和次要设备编号。

文件类型说明文件类型说明
S_IFBLK阻止特殊 S_IFREG常规文件
S_IFCHR特殊字符 S_IFDIR目录
S_IFIFO FIFO特殊 S_IFLNK符号链接
文件模式说明文件模式说明
S_IRWXU由所有者读取,写入,执行/搜索 S_IWGRP写权限,组
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),对其他用户则没有权限(0)。

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

#include <sys/types.h>
#include <sys/stat.h>

int mkfifo(const char *pathname, mode_t mode)

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

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

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

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

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

  • 以只读方式打开命名管道。

  • 此处,创建了具有Owner读写权限的FIFO。

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

  • 如果从客户端收到的消息不是"end",则打印该消息。如果消息为"end",则关闭fifo并结束该进程。

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

现在,让我们看一下FIFO服务器文件。

/* Filename: fifoserver.c */
#include <stdio.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>

#define FIFO_FILE "MYFIFO"
int main() {
   int fd;
   char readbuf[80];
   char end[10];
   int to_end;
   int read_bytes;
   
   /* Create the FIFO if it does not exist */
   mknod(FIFO_FILE, S_IFIFO|0640, 0);
   strcpy(end, "end");
   while(1) {
      fd = open(FIFO_FILE, O_RDONLY);
      read_bytes = read(fd, readbuf, sizeof(readbuf));
      readbuf[read_bytes] = '\0';
      printf("Received string:\"%s\" and length is %d\n", readbuf, (int)strlen(readbuf));
      to_end = strcmp(readbuf, end);
      if (to_end == 0) {
         close(fd);
         break;
      }
   }
   return 0;
}

编译和执行步骤

Received string: "this is string 1" and length is 16
Received string: "fifo test" and length is 9
Received string: "fifo client and server" and length is 22
Received string: "end" and length is 3

现在,让我们看一下FIFO客户端示例代码。

/* Filename: fifoclient.c */
#include <stdio.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>

#define FIFO_FILE "MYFIFO"
int main() {
   int fd;
   int end_process;
   int stringlen;
   char readbuf[80];
   char end_str[5];
   printf("FIFO_CLIENT: Send messages, infinitely, to end enter\"end\"\n");
   fd = open(FIFO_FILE, O_CREAT|O_WRONLY);
   strcpy(end_str, "end");
   
   while (1) {
      printf("Enter string: ");
      fgets(readbuf, sizeof(readbuf), stdin);
      stringlen = strlen(readbuf);
      readbuf[stringlen - 1] = '\0';
      end_process = strcmp(readbuf, end_str);
      
      //printf("end_process is %d\n", end_process);
      if (end_process != 0) {
         write(fd, readbuf, strlen(readbuf));
         printf("Sent string:\"%s\" and string length is %d\n", readbuf, (int)strlen(readbuf));
      } else {
         write(fd, readbuf, strlen(readbuf));
         printf("Sent string:\"%s\" and string length is %d\n", readbuf, (int)strlen(readbuf));
         close(fd);
         break;
      }
   }
   return 0;
}

让我们看一下到达的输出。

编译和执行步骤

FIFO_CLIENT: Send messages, infinitely, to end enter "end"
Enter string: this is string 1
Sent string: "this is string 1" and string length is 16
Enter string: fifo test
Sent string: "fifo test" and string length is 9
Enter string: fifo client and server
Sent string: "fifo client and server" and string length is 22
Enter string: end
Sent string: "end" and string length is 3

命名管道双向通讯

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

以下是一个示例-

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

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

  • 在/tmp目录(如果未创建)中创建名称为" fifo_twoway"的命名管道(使用库函数mkfifo())。

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

  • 此处,创建了具有Owner读写权限的FIFO。

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

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

    无涯教程网

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

现在,让我们看一下FIFO服务器示例代码。

/* Filename: fifoserver_twoway.c */
#include <stdio.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>

#define FIFO_FILE "/tmp/fifo_twoway"
void reverse_string(char *);
int main() {
   int fd;
   char readbuf[80];
   char end[10];
   int to_end;
   int read_bytes;
   
   /* Create the FIFO if it does not exist */
   mkfifo(FIFO_FILE, S_IFIFO|0640);
   strcpy(end, "end");
   fd = open(FIFO_FILE, O_RDWR);
   while(1) {
      read_bytes = read(fd, readbuf, sizeof(readbuf));
      readbuf[read_bytes] = '\0';
      printf("FIFOSERVER: Received string:\"%s\" and length is %d\n", readbuf, (int)strlen(readbuf));
      to_end = strcmp(readbuf, end);
      
      if (to_end == 0) {
         close(fd);
         break;
      }
      reverse_string(readbuf);
      printf("FIFOSERVER: Sending Reversed String:\"%s\" and length is %d\n", readbuf, (int) strlen(readbuf));
      write(fd, readbuf, strlen(readbuf));
      /*
      sleep - This is to make sure other process reads this, otherwise this
      process would retrieve the message
      */
      sleep(2);
   }
   return 0;
}

void reverse_string(char *str) {
   int last, limit, first;
   char temp;
   last = strlen(str) - 1;
   limit = last/2;
   first = 0;
   
   while (first < last) {
      temp = str[first];
      str[first] = str[last];
      str[last] = temp;
      first++;
      last--;
   }
   return;
}

编译和执行步骤

FIFOSERVER: Received string: "LINUX IPCs" and length is 10
FIFOSERVER: Sending Reversed String: "sCPI XUNIL" and length is 10
FIFOSERVER: Received string: "Inter Process Communication" and length is 27
FIFOSERVER: Sending Reversed String: "noitacinummoC ssecorP retnI" and length is 27
FIFOSERVER: Received string: "end" and length is 3

现在,让我们看一下FIFO客户端示例代码。

/* Filename: fifoclient_twoway.c */
#include <stdio.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>

#define FIFO_FILE "/tmp/fifo_twoway"
int main() {
   int fd;
   int end_process;
   int stringlen;
   int read_bytes;
   char readbuf[80];
   char end_str[5];
   printf("FIFO_CLIENT: Send messages, infinitely, to end enter\"end\"\n");
   fd = open(FIFO_FILE, O_CREAT|O_RDWR);
   strcpy(end_str, "end");
   
   while (1) {
      printf("Enter string: ");
      fgets(readbuf, sizeof(readbuf), stdin);
      stringlen = strlen(readbuf);
      readbuf[stringlen - 1] = '\0';
      end_process = strcmp(readbuf, end_str);
      
      //printf("end_process is %d\n", end_process);
      if (end_process != 0) {
         write(fd, readbuf, strlen(readbuf));
         printf("FIFOCLIENT: Sent string:\"%s\" and string length is %d\n", readbuf, (int)strlen(readbuf));
         read_bytes = read(fd, readbuf, sizeof(readbuf));
         readbuf[read_bytes] = '\0';
         printf("FIFOCLIENT: Received string:\"%s\" and length is %d\n", readbuf, (int)strlen(readbuf));
      } else {
         write(fd, readbuf, strlen(readbuf));
         printf("FIFOCLIENT: Sent string:\"%s\" and string length is %d\n", readbuf, (int)strlen(readbuf));
         close(fd);
         break;
      }
   }
   return 0;
}

编译和执行步骤

FIFO_CLIENT: Send messages, infinitely, to end enter "end"
Enter string: LINUX IPCs
FIFOCLIENT: Sent string: "LINUX IPCs" and string length is 10
FIFOCLIENT: Received string: "sCPI XUNIL" and length is 10
Enter string: Inter Process Communication
FIFOCLIENT: Sent string: "Inter Process Communication" and string length is 27
FIFOCLIENT: Received string: "noitacinummoC ssecorP retnI" and length is 27
Enter string: end
FIFOCLIENT: Sent string: "end" and string length is 3

这一章你学到了什么?来做个笔记,好记忆不如烂笔头! 如果觉得对您有帮助,麻烦帮分享给您的朋友。

祝学习愉快! (如果觉得不正确,选中要修改的内容->右键->编辑)

点我分享笔记