前提:原来也写过匿名管道的代码但是总觉得没有了解过底层,只是知道 管道是一个文件它存在与内存上,一般父子进程之间使用但是并没有研究过底层。所以这次参考linux内核情景分析这本书进行整理。(因为对linux虚拟文件系统的了解因此这次对于匿名管道也有多帮助毕竟他也是个文件哈哈哈哈哈开始吧)
它的系统调用是pipe();因为这是是在一个进程中调用的所以你懂得 必须要在有关系的进程间使用比如父子,或这子子,;
#include <unistd.h>
int pipe(int pipefd[2]);
基本的使用过程
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <unistd.h>
#include <string.h>
int main()
{
int fd[2];
assert(pipe(fd)!=-1);
pid_t pid=fork();
assert(pid!=-1);
if(pid==0)
{
close(fd[1]); //0是读端1是写端
while(1)
{
char buff[128]={0};
if(read(fd[0],buff,128)==0)
{
close(fd[0]);
break;
}
printf("%s\n",buff);
}
}
else
{
close(fd[0]);
while(1)
{
char buff[128]={0};
fgets(buff,128,stdin);
if(strncmp(buff,"end",3)==0)
{
close(fd[1]);
break;
}
write(fd[1],buff,127);
}
}
exit(0);
}
必须是一端读另一段写所以要关闭不许要的那一段要不有可能会出现问题具体自己想形象,半工的所以想让我们使用必须建立两个匿名管理进行双工通信,或者使用socketpair这个是双工。
pipe->sys_pipe() ->do_pipe
因为我前面的文章对虚拟文件系统有过叙述所以,每个fd所对应的都是一个stuct file结构体我们叫做文件表的东西。一个管道文件对文件的操作必须要在两个文件中进行,分别代表两端,所一虽然在两个进程中但是管道的两端是两个file结构体,当创建完之后一个file对文件的操作是只读,另一个 是写。所以不同问文件file获取的是不同的f_op 对于0端是写的f_op 对于读端的类似与其他啊。
所以get_empty_file 是从空闲的file链表获取两个file结构体,这个前面也说过这只是管理文件并不是文件。。
所以对于文件的偏移两个都是0;对于管道而言也是一个文件所以给他创建文件索引。创建inode,
获取到空间的inode然后将其指向自己的文件系统 pipe_mnt; 所以该inode对应的super块给了inode 。
对于 inode_fop 他的操作是super块提供的这个东西不同的文件系统给自己的inode文件是不同的。
inode 结构体中有一个i_pipe然后对于一般问价而言这个指针都是空但是对于管道文件指向的是一个结构体叫做
pipe_inode_info 这个结构体中定义了PIPE_READERS 和 PIPE_WRITERS两个宏这两个宏主要是在get_pipe_inode 中 使用的。 主要作用记录当前读者和写着的个数;
对于管道的i_op 因为他不是一般文件所以这为空。
接下来咱们对于一些情况进行分析dup2,这个函数好多人都是用过。具体的情况我不理解。
对于管道文件系统而言,read的底层实现。
sys_read()->pipe-read()
对于有数据了直接 去读就行如果没有数据是如何处理的?
具体参考代码
if(PIPE_EMPTY(*inode)){
do_more read:
ret =0;
if(!PIPE_WARTES(*inode))
{
go out;
}
ret =-EAGIN;
if(filp->f_flags & O_NONBLOCK)
{
go out;
}
for(;;)
{
PIPE_WAITING_READERS(*inode)++;
pipe_wait(inode);//设置节点休眠
PIPE_WAITING_READERS(*Inode)--;
if(signal_speng(current))//收到信号跳出去
{
go out;
}
if(!PIPE_EMPTY(*inode))//文件 中有数据跳出去
break;
if(!PIPE_WRITERS(*indoe))//写的个数为0跳出去
go out;}
基于上面我们可以想出几条懂
read时候可能会返回的情况对于阻塞的IO信号打断返回,有数据了返回,最后写者个数是0 返回。
对于设置了非阻塞的IO 没有数据会直接返回 -1 -EAGIN
一般来说管道的大小是4kb一般会给管道分配一个内存页当做自己的存储空间。所以read读到数据也会分为3中情况,1.刚好读完管道中的数据返回读到的个数,2,读的个数小于管道中的个数返回读的个数3读的多余管道中的返回管道中的。经过测试实际上在linux2.6.11版本之后pipe的大小为65536以前是4096;
对于write而言也有三种状况具体分析
当管道的读端关闭,如果继续写就会发生sigpipe
如果管道写满设置了阻塞就会阻塞;
如果是非阻塞管道满了的话就会返回-EAGIN (具体记性代码 部分分析)count 记录当前