命名管道(FIFO)与匿名管道(PIPE)的不同的地方在于,命名管道在文件系统中具有一个名字,可以使得不相关的进程也能通过该名字访问管道。
在Linux中可以使用mkfifo命令和mknod命令创建命名管道;mkfifo专用于创建命名管道(FIFO)。mknod命令用于创建设备文件,字符设备,块设备或FIFO。
mkfifo 命令非常简单,用法如下:
mkfifo <fifo_name>
mknod 命令稍微复杂一些,因为它需要指定设备类型。创建命名管道的命令如下:
mknod <fifo_name> p
例如创建一个命名管道my_fifo
mkfifo my_fifo
可以通过echo和cat命令操作FIFO进行读写,在两个终端中分别执行下面两条命令,执行cat的终端就会收到test!的信息;执行cat my_fifo后命名管道是阻塞的,直到有进程将数据写入my_fifo。
cat my_fifo
echo "test!" > my_fifo
在应用程序中也可以使用mkfifo命令的同名函数mkfifo()来创建FIFO;mknod()是比较老的函数,而使用mkfifo()函数更加简单和规范,所以建议在可能的情况下,尽量使用mkfifo()而不是mknod()。
mkfifo专用于创建命名管道(FIFO)。
1 .头文件
#include <sys/types.h>
#include <sys/stat.h>
2 .函数原型
int mkfifo(const char *pathname, mode_t mode);
3 .参数
pathname:表示要创建的命名管道的路径和名称。是一个字符指针,指定命名管道的路径,可以是相对路径或绝对路径。例如,/tmp/my_fifo 或 my_fifo(在当前目录下)。
mode:指定文件的权限模式。是一个 mode_t 类型的值,用于指定 FIFO 的访问权限,与 open() 或 chmod() 使用的权限模式类似。
权限值一般包括:
S_IRUSR (0400):用户可读
S_IWUSR (0200):用户可写
S_IRGRP (0040):组可读
S_IWGRP (0020):组可写
S_IROTH (0004):其他用户可读
S_IWOTH (0002):其他用户可写
例如,0666 表示用户、组和其他用户都可读写。
4 .返回值
函数成功返回 0,否则返回-1 并设置 errno,与其他文件一样,FIFO文件也可以使用open、read、write、close调用来进行读写。
5 .示例:通过mkfifo()函数创建命名管道通信
|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| #include <stdio.h> #include <stdlib.h> #include <sys/types.h> #include <sys/stat.h> #include <unistd.h> #include <fcntl.h> #include <string.h> #include <errno.h> int main() { const char *fifo_path = "/tmp/my_fifo"; char buffer256; pid_t pid; // 创建命名管道 if (mkfifo(fifo_path, 0666) == -1) { if (errno != EEXIST) { perror("mkfifo"); exit(EXIT_FAILURE); } } // 创建子进程 pid = fork(); if (pid == -1) { perror("fork"); exit(EXIT_FAILURE); } if (pid == 0) { // 子进程:写入数据 int fifo_fd = open(fifo_path, O_WRONLY); if (fifo_fd == -1) { perror("open for write"); exit(EXIT_FAILURE); } const char *message = "Hello from child process!"; write(fifo_fd, message, strlen(message) + 1); // +1 to include '\0' close(fifo_fd); printf("Child process: Wrote message to FIFO\n"); } else { // 父进程:读取数据 int fifo_fd = open(fifo_path, O_RDONLY); if (fifo_fd == -1) { perror("open for read"); exit(EXIT_FAILURE); } read(fifo_fd, buffer, sizeof(buffer)); printf("Parent process: Read message from FIFO: %s\n", buffer); close(fifo_fd); // 删除管道文件 unlink(fifo_path); } return 0; } |
6 .运行结果
|--------------------------------------------------------------------------------------------------------|
| Parent process: Read message from FIFO: Hello from child process! Child process: Wrote message to FIFO |
7 .程序解析
使用 mkfifo() 创建命名管道。父进程和子进程通过 fork() 创建,并通过 open()、write()、read() 函数进行通信。父进程在读取完数据后,删除命名管道文件。
将这个程序中的父子进程拆成两个程序,编译之后打开两个终端执行;writer 程序通过 mkfifo() 确保管道存在,然后打开管道写入数据。reader 程序打开管道读取数据,并在读取完数据后删除管道文件。
8 .写入数据的程序(writer.c)
|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| #include <stdio.h> #include <stdlib.h> #include <sys/types.h> #include <sys/stat.h> #include <unistd.h> #include <fcntl.h> #include <string.h> #include <errno.h> int main() { const char *fifo_path = "/tmp/my_fifo"; // 创建命名管道 if (mkfifo(fifo_path, 0666) == -1) { if (errno != EEXIST) { perror("mkfifo"); exit(EXIT_FAILURE); } } // 打开管道进行写入 int fifo_fd = open(fifo_path, O_WRONLY); if (fifo_fd == -1) { perror("open for write"); exit(EXIT_FAILURE); } const char *message = "Hello from writer program!"; write(fifo_fd, message, strlen(message) + 1); // +1 to include '\0' printf("Writer: Message written to FIFO\n"); close(fifo_fd); return 0; } |
9 .读取数据的程序(reader.c)
|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| #include <stdio.h> #include <stdlib.h> #include <sys/types.h> #include <sys/stat.h> #include <unistd.h> #include <fcntl.h> #include <string.h> #include <errno.h> int main() { const char *fifo_path = "/tmp/my_fifo"; char buffer256; // 打开管道进行读取 int fifo_fd = open(fifo_path, O_RDONLY); if (fifo_fd == -1) { perror("open for read"); exit(EXIT_FAILURE); } read(fifo_fd, buffer, sizeof(buffer)); printf("Reader: Message read from FIFO: %s\n", buffer); close(fifo_fd); // 删除管道文件 unlink(fifo_path); return 0; } |