管道创建主要是两种:无名管道和有名管道(命名管道)
无名管道(pipe函数)
- 需要的头文件:#include <unistd.h>
- 函数: int pipe(int pipefd[2]);
- 主要创建无名管道的方式:
int pipefd[2]; //名字随意
if(pide(pipefd)<0)
{
//创建失败就报错
perror("pipe");
exit(1);
}
- 返回值:成功为0,失败为-1
- 无名管道的受限范围:无名管道是用于血缘进程(父子进程)之间的通信,如果两个进程不是血缘进程,那么无法进行通信
- 无名管道原理:这种管道建立之后,他们会在进程中占用两个文件符的位置,一个专门来读,一个专门来写,如下的左图。具有方向性要么是父写子读,关闭父读子写,要么就是子写父读,关闭父写子读,他们之间是通过计算机的内核来实现的。看下图中,红黑箭头只能存在一种(箭头方向代表信息传递方向)。
无名管demo:
#include<sys/types.h>
#include<sys/stat.h>
#include<unistd.h>
#include<fcntl.h>
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
int fd[2];
pid_t pid;
//创建管道
if(pipe(fd) < 0)
{
//如果返回的是-1就代表创建失败,0代表成功
perror("pipe");
exit(1);
}
//创建父子进程
pid = fork();
char str[1024] = "hello linux\n";
char buf[1024];
//父进程
if(pid > 0)
{
close(fd[0]); //父进程关闭读
write(fd[1],str,strlen(str));
}
else if(pid == 0) //子进程
{
int len;
close(fd[1]); //子进程关闭写
len = read(fd[0],buf,sizeof(buf));
write(STDOUT_FILENO,buf,len); //以标准形式输出
}
else
{
perror("fork"); //进程异常处理
exit(1);
}
while(1);
return 0;
}
有名管道
有名管道用的是mkfifo,这个mkfifo有指令,也有函数。有名管道的原理和无名管道类似,都是通过一个中转的地方来通信,但是有名管道不是通过内核,而是通过磁盘创建一个节点来进行信号的中转,该节点不占空间。
有名管道特性
- 当只写打开FIFO管道时,如果没有FIFO没有读端打开,则open写打开会阻塞。
- FIFO内核实现时可以支持双向通信。(pipe单向通信,因为父子进程共享同一个file 结构体)
- FIFO可以一个读端,多个写端;也可以一个写端,多个读端
方法一:使用mkfifo函数
- 需要的头文件:#include <sys/types.h> 和 #include <sys/stat.h>
- 函数:int mkfifo(const char *pathname, mode_t mode)
- 参数解析:第一个参数为创建出来的的管道文件名称,第二个参数是该文件的权限
- 返回值:-1失败,0为成功
- 示例demo(这里我分三个文件来写)
创建有名管道的文件,该文件要先执行来创建一个管道
#include<sys/types.h>
#include<sys/stat.h>
#include<unistd.h>
#include<fcntl.h>
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
int ret;
//先删除一下文件,防止重复创建
unlink("FileTP");
//创建命名管道,权限为 rwx rwx rwx的文件(0表示无特殊权限s)
ret = mkfifo("FileTP",0777);
if(ret==0)
{
printf("创建命名管道成功\n");
}
else //返回值为-1
{
printf("创建失败\n");
}
return 0;
}
读数据端的文件
#include<sys/types.h>
#include<sys/stat.h>
#include<unistd.h>
#include<fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void)
{
int fd,len;
char buf[1024];
//打开命名管道
fd = open("FileTP",O_RDONLY);
if(fd == -1)
{
//输出报错,关闭程序
perror("文件打开失败\n");
exit(1);
}
len = read(fd,buf,sizeof(buf));
//write(STDOUT_FILENO,buf,len);
printf("%s\n",buf);
close(fd);
return 0;
}
写数据端的文件
#include<sys/types.h>
#include<sys/stat.h>
#include<unistd.h>
#include<fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void)
{
int fd;
char buf[] = "hello linux\n";
printf("开始运行\n");
fd = open("FileTP",O_WRONLY);
if(fd == -1)
{
//输出报错,关闭程序
perror("文件打开失败\n");
exit(1);
}
else
{
printf("成功打开了文件\n");
}
//写文件
write(fd,buf,sizeof(buf));
printf("写完了\n");
close(fd);
return 0;
}
注意:执行的时候,当只写打开FifeTP管道时,如果没有FifeTP没有读端打开,则open写打开会阻塞。即,你执行写文件的时候,程序是不走的,只有你打开另外一个终端执行读文件时,写文件的程序才会执行(用两个终端执行两个文件)
方法二:使用mkfifo指令
在终端输入mkfifo 管道名 来创建有名管道。方法和上面的一样,只是省去了创建管道文件那个操作。