有名管道是通过在磁盘上创建一个管道类型的文件, 不同的进程可以通过读写这个文件实现通信。
和无名管道一样, 有名管道也是半双工通信
类型, 同一时刻, 一端只能读, 另一端只能写。
与无名管道不同, 有名管道因为在磁盘上有实际的文件
存在, 所以, 任意两个本地进程
都可以通过这个管道文件实现通信。
有名管道注意点:
- 读端未打开时, 写端打开阻塞, 读端打开时, 阻塞结束
- 写端未打开时, 读端打开阻塞, 写端打开时, 阻塞结束
- 读端关闭, 写端写入时, 触发管道破裂信号(
SIGPIPE
) - 写端关闭, 读端读取时, 读取数据完毕后立即返回, 不再阻塞
- 读端不读取, 写端写入时, 管道写满后, 写端阻塞
- 写端不写入, 读端读取时, 读完管道内的数据后, 读端阻塞
- 读端关闭后, 写端不要写入, 读端再打开, 写端可以继续写入
- 写端关闭后, 读端不阻塞, 写端再打开, 读端继续阻塞
代码示例:
有名管道读端 read.c
/**
* Description: 有名管道读端
* File: read.c |Time: 2021-05-29 08:36
*/
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <strings.h>
#define PIPE_NAME "test.pipe"
#define BUF_SIZE 100
int main(int argc, const char *argv[])
{
if (access(PIPE_NAME, F_OK))
{
printf("pipe not exist.\n");
exit(EXIT_FAILURE);
}
char buf[BUF_SIZE] = {0};
int read_res = 0;
// 验证写端未打开时, 读端打开阻塞
printf("read open start\n");
int fd = open(PIPE_NAME, O_RDONLY);
printf("read open end\n");
if (fd < 0)
{
perror("open");
exit(EXIT_FAILURE);
}
// 从管道中读取并记录读取字节数
while ((read_res = read(fd, buf, sizeof(buf))) >= 0)
{
if (read_res < 0)
{
perror("read");
exit(EXIT_FAILURE);
}
printf("[read from pipe]%d:%s\n",read_res, buf);
bzero(buf, sizeof(buf));
sleep(1);
}
return 0;
}
有名管道写端 write.c
/**
* Description: 有名管道写端
* File: write.c |Time: 2021-05-29 08:36
*/
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <strings.h>
#include <string.h>
#define PIPE_NAME "test.pipe"
#define BUF_SIZE 100
int main(int argc, const char *argv[])
{
// 检查管道文件是否存在, 不存在则创建
if (access(PIPE_NAME, F_OK) < 0)
{
if (-1 == mkfifo(PIPE_NAME, 0777))
{
perror("mkfifo");
exit(EXIT_FAILURE);
}
}
// 验证读端未打开时, 写端打开会阻塞
printf("write open start\n");
int fd = open(PIPE_NAME, O_WRONLY, 0664);
printf("write open end\n");
if (fd < 0)
{
perror("open");
exit(EXIT_FAILURE);
}
char buf[BUF_SIZE] = {0};
sprintf(buf, "hello");
while(1)
{
printf("[to pipe]");
// 阻塞1: 阻塞等待输入
fgets(buf, BUF_SIZE, stdin);
buf[strlen(buf) - 1] = '\0';
// 阻塞2: 阻塞等待从管道中读取
write(fd, buf, strlen(buf));
bzero(buf, sizeof(buf));
}
if (close(fd) < 0)
{
perror("close");
exit(EXIT_FAILURE);
}
return 0;
}