有名管道(Named Pipe),也称为FIFO(First In, First Out),是一种特殊的文件系统对象,它允许不相关的进程之间的通信。与无名管道不同,有名管道在文件系统中有一个路径名,因此不相关的进程可以通过这个路径名来访问同一个有名管道。
原理
有名管道的原理是基于FIFO队列的先进先出的数据结构。数据写入有名管道的一端,然后从另一端读取。有名管道在文件系统中以特殊文件的形式存在,通常具有FIFO
或pipe
类型。
int mkfifo(const char *pathname, mode_t mode);
pathname
:有名管道的路径名。mode
:有名管道的权限模式,通常使用八进制数(如0666
)。- 返回值:
- 成功时返回
0
。 - 失败时返回
-1
,并设置errno
以指示错误原因,可能的错误包括EACCES
(权限不足)EEXIST
(管道已存在)
ENAMETOOLONG
(路径名太长)等。
- 成功时返回
使用方法
-
创建有名管道
使用
mkfifo
命令或mkfifo
系统调用在文件系统中创建一个有名管道。-
使用
mkfifo
命令:bash
mkfifo mypipe
这将在当前目录下创建一个名为
mypipe
的有名管道。 -
使用
mkfifo
系统调用:#include <sys/types.h> #include <sys/stat.h>int mkfifo(const char *pathname, mode_t mode);
pathname
是有名管道的路径名,mode
是权限模式。
-
-
写入有名管道
使用
write
系统调用或库函数write()
向有名管道写入数据。#include <unistd.h> ssize_t write(int fd, const void *buf, size_t count);
首先,需要打开有名管道:
int fd = open("mypipe", O_WRONLY);
然后写入数据:
const char *message = "Hello, FIFO!"; write(fd, message, strlen(message));
-
从有名管道读取
使用
read
系统调用或库函数read()
从有名管道读取数据。#include <unistd.h> ssize_t read(int fd, void *buf, size_t count);
首先,需要打开有名管道:
int fd = open("mypipe", O_RDONLY);
然后读取数据:
char buffer[100]; read(fd, buffer, sizeof(buffer));
-
关闭有名管道
使用
close
系统调用或库函数close()
关闭有名管道的文件描述符。#include <unistd.h> int close(int fd);
close(fd);
-
删除有名管道
使用
unlink
系统调用或库函数unlink()
删除有名管道unlink("mypipe");
示例代码
以下是一个简单的有名管道使用示例,包括一个写入端和一个读取端。
创建端(creat.c):
#include <sys/stat.h>
#include <unistd.h>
#include <stdio.h>
int main(){if(mkfifo("myfifo",0666) == -1){perror("myfifo");return 0;}return 0;
}
写入端(writer.c):
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>
int main(){int fd;char buf[50];fd=open("myfifo",O_WRONLY);if( fd==-1 ){perror("open");return 1;}while(1){ bzero(buf,sizeof(buf));fgets(buf,sizeof(buf),stdin);if( write(fd,buf,strlen(buf)+1) == -1 ){perror("write");close(fd);return 0;}}close(fd);return 0;
}
读取端(reader.c):
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
int main(){int fd;char buffer[100];fd = open("myfifo",O_RDONLY);if(fd==-1){perror("open");return 1;}while(1){ if(read(fd,buffer,sizeof(buffer))==-1){perror("read");close(fd);return 0;}printf("收到信息:%s\n",buffer);}close(fd);return 0;
}
注意事项
- 权限问题:创建有名管道时,需要确保进程有足够的权限。
- 阻塞与非阻塞:有名管道的读写操作默认是阻塞的。如果需要非阻塞操作,可以设置文件描述符的非阻塞属性。
- 数据完整性:有名管道不保证数据的完整性,如果需要确保数据完整性,可以使用消息队列等其他IPC机制。
- 同步问题:有名管道不提供同步机制,如果需要同步,可以使用信号量等同步工具。
有名管道是一种简单有效的进程间通信方式,适用于需要通过文件系统路径进行通信的场景。