我们使用一根管道进行单向通信,而使用两条管道进行双向通信。同样的条件适用于命名管道,因为命名管道支持双向通信,所以我们可以使用可用于双向通信(服务器和客户端之间的通信,以及客户端和服务器之间的通信)的单个命名管道。
命名管道的另一个名称是 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 - 客户进程执行以下操作-
打开命名管道仅用于写目的。
接受来自用户的字符串。
检查用户输入的是" end"还是" end"以外的内容。无论哪种它都会向服务器发送一条消息。但是,如果字符串为" end",则关闭FIFO并结束进程。
无限重复,直到用户输入字符串" end"。
现在,让我们看一下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())。
打开命名管道以进行读写。
链接:https://www.learnfk.comhttps://www.learnfk.com/process/inter-process-communication-named-pipes.html
来源:LearnFk无涯教程网
此处,创建了具有Owner读写权限的FIFO。
无限等待来自客户端的消息。
如果从客户端收到的消息不是" end",则打印消息并反转字符串。反向的字符串将发送回客户端。如果消息为"end",则关闭fifo并结束该进程。
步骤3 - 客户进程执行以下操作-
打开命名管道以进行读写。
链接:https://www.learnfk.comhttps://www.learnfk.com/process/inter-process-communication-named-pipes.html
来源:LearnFk无涯教程网
接受来自用户的字符串。
检查用户输入的是" end"还是" end"以外的内容,它会向服务器发送一条消息。但是如果字符串为" end",则会关闭FIFO并结束进程。
如果消息不是" end"发送的,它将等待来自客户端的消息(反向字符串)并打印反向字符串。
无限重复,直到用户输入字符串" end"为止。
现在,让我们看一下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
祝学习愉快!(内容编辑有误?请选中要编辑内容 -> 右键 -> 修改 -> 提交!)