管道
- 本质:连接一个进程和另一个进程之间的数据流,是内核提供的一段内存,通过文件描述符来管理管道。fd[0]读数据,fd[1]写数据。
而管道又可分为匿名管道和命名管道两种。
匿名管道
int pipe(int pipefd[2])
这个是匿名管道的创建,用pipe来实现。
匿名管道只能用于具有亲缘关系的进程之间进行通信。一般的时候,一个进程会创建一个管道,然后fork出一个子进程,通过管道进行数据的交流。
- 匿名管道是半双工的(单向通信),如果需要双方通信,则再创建一个管道。
- 一般来说,进程退出之后,管道机就释放,所以管道的生命周期是随着进程的。内核会对管道进行同步互斥操作。
- 从内核角度看管道的本质
接下来介绍管道的另一种,命名管道
命名管道
命名管道可以让不想关的进程进行交互,可以应用于任何管道之间
- 有两种创建方式:在命令行和程序中 -
命令行创建
localhost 0801]$ mkfifo filename
//程序中创建
int main(int argc,char *argv[]){
mkfifo("zyx",0644);//zyx是指向管道读端和写端的指针,0644是读写权限
int infd;
infd=open("abc",O_RDONLY);//用open打开读端,读取文件中的文本
if(infd==-1)
{
ERR_EXIT("open");
}
int outfd;
outfd=open("zyx",O_WRONLY);//用open打开写端
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)
//所以,流程为open->read->write->close.这个是通用的
//区别在于从哪里读,往哪里写
- 还可以用命名管道来实现服务器和客户端的交互
//serevr端
#include<stdio.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<unistd.h>
#include<stdlib.h>
int main()
{
umask(0); //允许进程创建文件时有最大权限
if(mkfifo("mypipe",0644)<0)
{
perror("mkfifo");
exit(1);
}
int rfd=open("mypipe",O_RDONLY); //只读模式
if(rfd<0)
{
perror("open");
exit(1);
}
char buf[1024]; //缓冲区
while(1)
{
buf[0]=0;
printf("please wait....\n");
ssize_t s=read(rfd,buf,sizeof(buf)-1); //读取来自客户端的数据到buf中
if(s>0)
{
buf[s-1]=0;
printf("client say # %s\n",buf);//读取成功,可以开始进行交互
}
else if(s==0)
{
printf("server quit");
exit(0);
}
else
{
perror("read");
exit(1);
}
}
close(rfd); //关闭读取
return 0 ;
}
//client端
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<sys/types.h>
int main()
{
int wfd=open("mypipe",O_WRONLY); //只写方式
if(wfd<0)
{
perror("open");
exit(1);
}
char buf[1024];
while(1)
{
buf[0]=0;
printf("please enter#");
fflush(stdout); //每次都要刷新,防止数据叠加在一起
ssize_t s=read(0,buf,sizeof(buf)-1); //从当前的光标或者键盘输入读入buf中
if(s>0)
{ //读取成功
buf[s]=0;
write(wfd,buf,sizeof(buf)-1); //将数据写入buf中
}
else if(s<=0)
{
perror("read"); //读取失败
exit(1);
}
}
close(wfd); //关闭写入
return 0 ;
}
结果展示