前提引入: 我们之前接触过管道 | 将前一个命令的输出结果作为后一个命令的输入
如:ps | grep “sleep”
其实就是将 ps 的结果写入到一个区域,在从这个区域读出目标数据
创建管道文件 : mkfifo fifo ->创建一个名为fifo的管道文件
如图,管道文件的大小为0,是因为他是在内存中写入,读取,并不会占用磁盘空间,因此速度会快很多。
管道文件只有:只读,只写两种权限。
1.执行写入文件a.c
#include
#include
#include
#include
#include
#include
int main()
{
int fd = open("fifo",O_WRONLY);
if(fd == -1)
{
printf("none file\n");
exit(1);
}
char buff[128];
while(1)
{
printf("intput:");
fflush(stdout);
fgets(buff,128,stdin);
buff[strlen(buff)-1]=0;
if(strcmp(buff,"end") == 0)
{
break;
}
write(fd,buff,strlen(buff));
}
close(fd);
exit(0);
}
2.执行读取文件 b.c
#include
#include
#include
#include
#include
#include
int main()
{
int fd = open("fifo",O_RDONLY);
if(fd == -1)
{
printf("none file\n");
exit(1);
}
printf("fd = %d\n",fd);
while(1)
{
char buff[128]={0};
int n = read(fd,buff,127);
if(n != 0)
{
printf("%s\n",buff);
}
else
{
break;
}
}
close(fd);
exit(0);
}
管道文件必须同时被只读,只写打开,否则无法成功打开
1.只写无法打开
2.只读无法打开
3.正确方式:只读,只写同时打开
写端关闭,读端read返回0,退出循环
读端关闭,写端write时会收到异常信号(SIGPIPE),进而结束该进程
验证是否产生该信号
写端a.c 测试代码:
#include
#include
#include
#include
#include
#include
#include
void fun_sig(int sig)
{
printf("%d,%d\n",sig,13 == sig);
}
int main()
{
signal(SIGPIPE,fun_sig);
int fd = open("fifo",O_WRONLY);
if(fd == -1)
{
printf("none file\n");
exit(1);
}
char buff[128];
while(1)
{
printf("intput:");
fflush(stdout);
fgets(buff,128,stdin);
buff[strlen(buff)-1]=0;
if(strcmp(buff,"end") == 0)
{
break;
}
write(fd,buff,strlen(buff));
}
close(fd);
exit(0);
}
如图:
利用函数 int pipe(int fds[2]);
int pipe(int fds[2]);
pipe()成功返回 0,失败返回-1
fds[0]是管道读端的描述符
fds[1]是管道写端的描述符
测试代码:
#include
#include
#include
#include
#include
#include
#include
int main()
{
int fd[2];
if(pipe(fd) == -1) exit(1);
int pid = fork();
if(pid == 0)
{
close(fd[0]);
printf("child input\n");
write(fd[1],"hello",6);
}
else
{
char buff[128]={0};
close(fd[1]);
printf("parent read:");
read(fd[0],buff,127);
printf("%s\n",buff);
}
exit(0);
}
如图:
无名管道主要应用于父子进程间的通信。
◼ 无论有名还是无名,写入管道的数据都在内存中
◼ 管道是一种半双工通信方式(通信方式有单工、半双工、全双工)
◼ 有名和无名管道的区别:有名可以在任意进程间使用,而无名主要在父子进程间