一、什么是管道
管道是从unux继承过来的最早的IPC通讯方式之一,它有如下特点:
- 管道数据的读写是半双工的,即只能从写端写入,从读端读出;
- 管道数据不能重复读取,一旦调用read读取写入管道的数据,这段数据将永久从管道中移除,不能被其它进程获取;
- 管道有点类似于队列,允许用户向其中连续放入多条内容,然后可以逐条取出;
二、有名管道和无名管道
2.1、无名管道
- 无名管道的存在依赖于创建它的进程,当进程退出后,无名管道的资源也会自动释放;
- 无名管道通信只能用于具有亲缘关系的进程之间的通讯(有名管道没有这个限制);
2.2、有名管道
- 有名管道也叫FIFO,它在linux系统中作为一种特殊的文件而存在,并具有文件系统中的inode信息。
- 有名管道(FIFO)创建之后是独立存在的,它不依赖于创建它的进程,因此任何进程可以根据FIFO的名称来打开并进行读写操作;
- 读写FIFO的两个进程调用open打开同一个FIFO文件是会得到相同的文件描述符;
- 有名管道(FIFO)在创建之后如果不再使用,需要主动删除,否则它会一直存在于系统之中;
- 我们可以把FIFO简单理解成一个文件,只是FIFO不能用open或者create等普通文件的创建方式来创建,而需要用mkfifo函数来创建。使用mkfifo创建一个FIFO之后,我们就可以把FIFO当成普通文件来使用open打开,使用read和write进行读写。
四、管道相关函数
4.1、pipe函数
int pipe(int pipefd[2]);
- pipe创建一个无名管道,pipfd用于指向管道两端的描述符。fppfd[0]指向读端,pipfd[1]指向管道的写端;
- 数据从管道写段写入,从管道读端读出,使用pipe创建得到的pipefd指向的是内存中的某一块内存,这块内存由系统分配,之后可以调用read和write对pipefd进行读写操作。
4.2、mkfifo函数
#include <sys/types.h>
#include <sys/stat.h>
int mkfifo(const char *pathname, mode_t mode);
- mkfifo用来创建一个有名管道(FIFO),它的第一个参数指定一个路径名,mode指定FIFO的权限,如0666表示具有可读和可写权限。
- mkfifo调用成功返回0,失败返回-1。
示例:
fifo_read.c
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
int main()
{
int ret = -1;
char *path = "/myfifo";
char buffer[1024];
int fd = -1;
if(0 != access(path,F_OK))//如果文件不存在,创建FIFO文件
{
ret = mkfifo(path,0666);
if(0 != ret)
{
perror("mkfifo error\r\n");
return -1;
}
}
fd = open(path,O_RDONLY);
if(0 > fd)
{
perror("open fifo error\r\n");
return -1;
}
printf("read fifo fd:%d\r\n",fd);
while(1)
{
memset(buffer,0,sizeof(buffer));
if(read(fd,buffer,sizeof(buffer))<=0)
{
perror("read error");
break;
}
printf("read fifo:%s",buffer);
if(0 == strncmp(buffer,"exit",4))
{
break;
}
}
printf("read process exit\r\n");
close(fd);
}
fifo_write.c
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
int main()
{
int ret = -1;
char *path = "/myfifo";
char buffer[1024];
int fd = -1;
if(0 != access(path,F_OK))//如果文件不存在,创建FIFO文件
{
ret = mkfifo(path,0666);
if(0 != ret)
{
perror("mkfifo error\r\n");
return -1;
}
}
fd = open(path,O_WRONLY);
if(0 > fd)
{
perror("open fifo error\r\n");
return -1;
}
printf("write fifo fd:%d\r\n",fd);
while(1)
{
printf("write some data:");
ret = fgets(buffer,1024,stdin);
if(write(fd,buffer,sizeof(buffer))<0)
{
perror("write error");
break;
}
if(0 == strncmp(buffer,"exit",4))
{
break;
}
}
printf("write process close fd\r\n");
close(fd);
}
gcc fifo_write.c -o write
gcc fifo_read.c -o read
分别在两个shell中运行read和write,运行结果如下