【什么是管道】
(1)管道是Unix中最古老进程间通信的形式
(2)我们把从一个进程连接到另一个进程的一个数据流称为一个“管道”。
【匿名管道】( pipe )
管道是IPC最基本的一种实现机制。我们都知道在Linux下“一切皆文件”,其实这里的管道就是一个文件。管道实现进程通信就是让两个进程都能访问该文件。
管道的特征:
①只提供单向通信,也就是说,两个进程都能访问这个文件,假设进程1往文件内写东西,那么进程2 就只能读取文件的内容。
②只能用于具有血缘关系的进程间通信,通常用于父子进程建通信
③管道是基于字节流来通信的
④依赖于文件系统,它的生命周期随进程的结束结束(随进程)
⑤其本身自带同步互斥效果
要实现管道,我们需了解两个函数:
(1)创建管道:
pipe—->创建一个匿名管道。
返回值:成功返回0,失败返回-1。
(2)创建子进程:
注:包含在头文件 “unistd.h” 中,无参数,返回值类型为 pid_t
返回值:调用成功将子进程的 pid 返回给父进程,失败返回-1给父进程。
注意:调用成功会有两个返回值,对于父进程,返回的是子进程的pid;对于子进程,返回的是0。
实例:
//从键盘读取数据,写入管道,读取管道,写到屏幕
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
int main()
{
int fds[2]; //存放标识符,0为读,1为写。
char buf[100];
int len;
if(pipe(fds)==-1)
perror("make pipe"),exit(1);
//read from stdin
while(fgets(buf,100,stdin))
{
len=strlen(buf);
//write into pipe
if(write(fds[1],buf,len)!=len)
{
perror("write to pipe");
break;
}
memset(buf,0x00,sizeof(buf));
//read from pipe
if((len=read(fds[0],buf,100))==-1)
{
perror("read from pipe");
break;
}
//write to stdout
if(write(1,buf,len)!=len)
{
perror("write to stdout");
break;
}
}
return 0;
}
【命名管道】
上述管道虽然实现了进程间通信,但是它具有一定的局限性:首先,这个管道只能是具有血缘关系的进程之间通信;第二,它只能实现一个进程写另一个进程读,而如果需要两者同时进行时,就得重新打开一个管道。
为了使任意两个进程之间能够通信,就提出了命名管道(named pipe 或 FIFO)。
1、与匿名管道的区别:提供了一个路径名与之关联,以FIFO文件的形式存储于文件系统中,能够实现任何两个进程之间通信。而匿名管道对于文件系统是不可见的,它仅限于在父子进程之间的通信。
2、 FIFO是一个设备文件,在文件系统中以文件名的形式存在,因此即使进程与创建FIFO的进程不存在血缘关系也依然可以通信,前提是可以访问该路径。
3、 FIFO(first input first output)总是遵循先进先出的原则,即第一个进来的数据会第一个被读走。
【命名管道的创建】:
1.可在命令行上创建:
$ mkfifo filename
2.在程序里创建:
int mkfifo (const char* filename , mode_t mode);
注释:filename 为管道名称;mode 为权限
实例:
//读取文件,写入命名管道
#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<string.h>
#include<errno.h>
#include<fcntl.h>
#define ERR_EXIT(m)\
do\
{\
perror(m);\
exit(EXIT_FAILURE);\
}while(0)
int main(int argc,char* argv[])
{
mkfifo("tp",0644);
int infd;
infd=open("abc",O_RDONLY);
if(infd==-1)
ERR_EXIT("open");
int outfd;
outfd=open("tp",O_WRONLY);
if(outfd==-1)
ERR_EXIT("open");
char buf[1024];
int n;
while((n=read(infd,buf,1024))>0)
{
write(outfd,buf,n);
}
close(infd);
close(outfd);
return 0;
}
//读取管道,写入文件
#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<string.h>
#include<errno.h>
#include<fcntl.h>
#define ERR_EXIT(m)\
do\
{\
perror(m);\
exit(EXIT_FAILURE);\
}while(0)
int main(int argc,char* argv[])
{
int outfd;
outfd=open("abc.bak",O_WRONLY | O_CREAT | O_TRUNC,0644);
if(outfd==-1)
ERR_EXIT("open");
int infd;
infd=open("tp",O_RDONLY);
if(infd==-1)
ERR_EXIT("open");
char buf[1024];
int n;
while((n=read(infd,buf,1024))>0)
{
write(outfd,buf,n);
}
close(infd);
close(outfd);
unlink("tp");
return 0;
}