Linux c 管道文件-进程间的通信 mkfifo、pipe
管道文件:
1. 创建管道mkfifo(命名管道)
#include<sys/stat.h>
int mkfifo( const char *pathname, mode_t mode);
参数:pathname:管道文件名/路径+文件名
Mode: 文件权限
返回值:0成功,-1失败
2. 体会管道文件的特点
案例:
fifoA fifoB
建立管道 打开管道
打开管道 读数据
写数据 关闭管道
关闭管道
删除管道
代码:
fifoA.c
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<fcntl.h>
#include<sys/stat.h>
#include<signal.h>
int fd;
void end( int s)
{
//关闭文件、删除管道文件
close(fd);
unlink( “text.pipe” );
exit(-1);
}
void main()
{
int i=0;
signal( SIGINT , end);
//创建管道
mkfifo( “text.pipe” , 0666);
//打开文件
fd=opend( “text.pipe”, O_RDWR);
//循环写入数据
while(1)
{
write(fd, & i , 4);
sleep(1);
i++;
}
}
fifoB.c
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/stat.h>
#include<signal.h>
int fd;
void end( int s)
{
//关闭文件
close(fd);
exit(-1);
}
void main()
{
int i=0;
signal( SIGINT , end);
//打开文件
fd=opend( “text.pipe”, O_RDWR);
//循环读取数据
while(1)
{
read(fd, & i , 4);
printf(“%d”,i);
}
}
程序运行说明:
程序A运行后往管道文件中写入数据,程序B从管道文件中读取数据,当程序B结束,程序A运行,并稍后程序B继续运行时,程序B读到的数据是继续上次结束时的下一个数据。
当程序A结束,程序B运行时,程序B阻塞挂起。
总结:
1. read没有数据,read会阻塞,而且read后数据是被删除。
2. 数据是有序的
3. 打开的描述符号可以读写(two-way双工)(建议用只读或只写打开)
或者用shutdown函数关闭读或写关闭,变成单工
4. 管道文件关闭后,数据不持久.(程序如不删除管道,程序结束后,无法读到数据)
5. 管道的数据实际是存储在内核的缓冲中。(管道文件不是一个真实的文件,是内存的虚拟文件)
注:其实管道文件只是内存中的一个先进先出的数据结构,文件只是个载体,打开管道文件时只是对应了描述符是一个先进先出的内存结构而不是一个真实的文件。(当我们的程序运行后,我们删除那个文件,程序可照常运行不受任何影响)
匿名管道:
发现有名的管道的名字仅仅是内核识别是否返回同一个fd的标示.
所以当管道名失去表示作用的时候,实际可以不要名字.
在父子进程之间:打开文件描述后创建进程.
父子进程都有描述符号. 管道文件没有价值.
所以在父子进程中引入一个没有名字的管道:匿名管道.
结论:
匿名管道只能使用在父子进程.
案例:
匿名管道的创建
体会匿名管道的特点
函数:
#include<unistd.h>
int pipe( int filedes[2] );
参数:数组指针(返回值),返回两个文件描述符
fd[0]:只读(不能写)
fd[1]:只写(不能读)
返回值:0成功、-1失败
pipe函数做了:
创建管道 打开管道 拷贝管道(两个) 关闭读写(一个关闭读,一个关闭写)
例子:
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
void main()
{
int fd[2];
int r;
char buf[20];
r=pipe(fd);
write( fd[1] , “hello” , 5);
write(fd[1] , “world”, 5);
r=read( fd[0], buf, 20);
buf[r]=0;
printf(“%s\n”,buf);
}
父子进程例子:
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
void main()
{
int fd[2];
pipe( fd );
if(fork())
{
//parent
close(fd[0]); //只负责写入数据
while(1)
{
write( fd[1] ,”hello”);
sleep(1);
}
}
else
{
//child
close(fd[1]); //只负责读数据
char buf[20];
int r;
while(1)
{
r=read( fd[0] , buf , 20);
buf[r]=0;
printf(“::%s\n”,buf);
}
}
}
注:建议一个进程的一个匿名管道只负责读或写,不要即读即写,否则会导致数据混乱。所以,上面的程序父进程关闭了读文件描述符,子进程关闭了写文件描述符。父进程只负责写入数据,子进程只负责读取数据。