前言
在进程间通信的几种方式中,管道可谓是最简单的了,今天我们就来介绍一下两种管道的用法。
一、无名管道
1.概念介绍
无名管道和有名管道是Linux系统内核的特殊文件,用于进程之间的通信。
无名管道相当于一个队列结构,fd[1]为写入端(入队),fd[0]为读出端(出队)。其中信息读出后即删除,再次读取时即为下一个信息。
2.相关函数介绍
函数形式:int pipe(int fd[2])
功能:创建无名管道文件。无名管道是一个特殊文件,不可由open函数创建。
参数:fd[2]有两个成员 fd[0]和 fd[1],他们都是文件描述符。 管道有固定的读端 fd[0]和固定的写端 fd[1]。
返回值:成功返回 0,出错返回-1。
3.关于无名管道的一些说明
①管道是创建在内存中,进程结束空间释放,管道不复存在。
②无名管道和有名管道都是半双工通信,实现双向通信需要建立两个管道。
③无名管道是linux特殊文件,不能在与windows共享的文件夹中创建。
④无名管道只用于父子进程之间,有名管道可用于无亲缘关系的进程之间
4.无名管道编程实战
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
int main()
{
int fd[2];
int pid;
char buf[128];
if(pipe(fd)==-1){
printf("creat pipe failur\n");//创建一个无名管道
}
pid=fork();//获取fork后的pid号
if(pid<0){
printf("creat child failur\n");
}else if(pid>0){
sleep(3);
printf("thid is father\n");
close(fd[0]);
write(fd[1],"wencai love pingping",strlen("wencai love pingping"));//将要传递的数据写入fd这个数组中
wait();//父进程等待子进程
}else{
printf("this is child\n");
close(fd[1]);
read(fd[0],buf,128);//读取管道中的数据
printf("read from father:%s\n",buf);
exit(0);
}
return 0;
}
无名管道在进行通信时不能同时读写,因而在读的这一段需关闭写,而在写的一端则需关闭读,下面我们来看看程序运行后的实际效果
可以看到通过无名管道成功的将一串字符串从父进程传递到了子进程。
二、有名管道
1.概念
有名管道是一种文件类型,在文件系统中可以看到。程序中可以查看文件stat结构中st_mode成员的值来判断文件是否是FIFO文件。创建一个FIFO文件类似于创建文件,FIFO文件就像普通文件一样。FIFO中可以很好地解决在无关进程间数据交换的要求,并且由于它们是存在于文件系统中的,这也提供了一种比匿名管道更持久稳定的通信办法。
FIFO的通信方式类似于在进程中使用文件来传输数据,只不过FIFO类型文件同时具有管道的特性。在数据读出时,FIFO管道中同时清除数据。在shell中mkfifo命令可以建立有名管道,下面通过编程实战来帮助读者理解FIFO。
2.编程实战
有名管道一般用的多的是令其堵塞,因而在创建管道后开始读取时,需要另一进程进行写,才能正确读取到。
创建有名管道编程及写入数据:
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <string.h>
int main()
{
int fd;
int n_write;
int cnt;
cnt=0;
char *str="wencai love pingping";//要发送的数据,可自己决定
fd=open("./file1",O_WRONLY);
printf("open sucesess\n");
while(1){
n_write=write(fd,str,strlen(str));
sleep(1);
cnt++;
if(cnt==4){
break;
}
}
close(fd);
return 0;
}
读取管道中的数据:
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <string.h>
int main()
{
int fd;
int n_read;
int cnt=0;
char buf[30]={0};
if((mkfifo("./file1",0600)==-1)&&errno!=EEXIST){ //查看是否有创建成功的管道
printf("creat failuer\n");
perror("why");
}
fd=open("./file1",O_RDONLY);
printf("open sucesess\n");
while(1){
memset(buf,'\0',sizeof(buf));//清空收到的消息
n_read=read(fd,buf,30);//读取管道中的数据
printf("read %d byte from,context:%s\n",n_read,buf);
if(cnt++==4){
break;
}
}
close(fd);
return 0;
}
然后我们在liunx平台下检查代码的运行效果
可以看到,通过写入与读取操作,我们完成了在两个不同进程间的通信
总结
管道是liunx平台下最古老的进程间通信的方式,虽然目前已经有了其他多种进程间通信的方式,但对于管道的学习还是有必要的。