命名管道
虽然匿名管道是一个文件,但匿名管道并不存在于文件系统中,所以匿名管道只能用于父子进程间的通信。没有血缘关系的进程,由于不存在文件描述符的继承,所以无法使用匿名管道进行通信,但可以使用命名管道进行通信。
创建一个命名管道可以使用 mkfifo 函数,mkfifo 函数指定了命名管道的设备文件路径,其他进程可以使用标准的文件打开函数—— open 函数打开该命名管道,然后使用 read 函数和 write 函数对命名管道进行读和写操作。
命名管道操作
命名管道的创建
#include <unistd.h>
int mkfifo(const char *pcFifoName, mode_t mode);
函数 mkfifo 原型分析:
- 此函数成功返回错误号 0,失败返回-1 并设置错误号。
- 参数 pcFifoName 指定了命名管道的设备文件路径。
- 参数 mode 指定了命名管道的设备文件模式,与 open 函数的模式位相同。
创建命名管道类似于创建文件,因此命名管道的路径名存在于文件系统中。
命名管道的打开
由于命名管道存在于文件系统中,所以可以使用标准的文件打开函数—— open 函数打开命名管道。调用 open 函数时参数 iFlag 是命名管道的打开标志,参数 iFlag 除了可以使用匿名管道的文件标志,还可以使用以下标志。
宏名 | 含义 |
---|---|
O_RDONLY | 以只读方式打开管道 |
O_WRONLY | 以只写方式打开管道 |
O_RDWR | 以读写方式打开管道 |
命名管道的读写
read 函数和 write 函数:命名管道的读和写操作分别使用标准的文件读写函数。
命名管道的等待
在命名管道为空或满时,读或写命名管道操作将被阻塞(除非使用 open 函数打开命名管道时参数 iFlag 指定了 O_NONBLOCK 选项),而等待一个命名管道可读或可写,可以调用 select 函数。
命名管道的关闭
close 函数:关闭一个命名管道可以使用标准的文件关闭函数。
命名管道的删除
unlink 函数:命名管道的删除使用标准的文件删除函数。
下面程序展示了命名管道的使用方法,程序由客户端程序和服务器程序组成,在服务器程序端创建命名管道文件“/dev/fifo”,并向管道中写入数据,客户端程序打开该文件并从管道中读取数据。
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#define FIFO_NAME "/dev/fifo"
#define SEND_STR "From server."
int main (int argc, char *argv[])
{
int fd;
char buf[64] = {0};
int i;
fd = open(FIFO_NAME, O_RDWR);
if (fd < 0) {
fprintf(stderr, "open fifo error.\n");
return (-1);
}
for (i = 0; i < 10; i++) {
read(fd, buf, strlen(SEND_STR));
fprintf(stdout, "read \"%s\" from fifo.\n", buf);
sleep(1);
}
close(fd);
return (0);
}
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#define FIFO_NAME "/dev/fifo"
#define SEND_STR "From server."
int main (int argc, char *argv[])
{
int ret, i;
int fd;
ret = mkfifo(FIFO_NAME, 0777);
if (ret < 0) {
perror("mkfifo");
fprintf(stderr, "mkfifo error.\n");
return (-1);
}
fd = open(FIFO_NAME, O_RDWR);
if (fd < 0) {
fprintf(stderr, "open fifo error.\n");
return (-1);
}
for (i = 0; i < 10; i++) {
write(fd, SEND_STR, strlen(SEND_STR));
fprintf(stdout, "write \"%s\" to fifo.\n", SEND_STR);
sleep(1);
}
sleep(5);
close(fd);
unlink(FIFO_NAME);
return (0);
}