一、无名管道pipe:
1. 无名管道特点:
1)只能用于具有亲缘关系的进程之间的通信。
2)半双工的通信模式,具有固定的读端和写端。
3)管道可以看成是一种特殊的文件,对于它的读写可以使用文件IO如read、write函数。
2.管道创建与关闭
1)管道是基于文件描述符的通信方式。当一个管道建立时,它会创建两个文件描述符fd[0]和fd[1]。其中fd[0]用于读,fd[1]用于写管道。
2)构成了一个半双工的通道。
函数pipe()
头文件:#include<unistd.h>
函数原型:int pipe(int fd[])
函数参数:fd[] 包含两个文件描述符的数组,其中fd[0]固定用于读管道,fd[1]固定用于写管道
函数返回值:成功:0
失败:-1
创建管道使用pipe()函数,而其余的操作诸如读取管道read()、写入管道write()、关闭管道close()函数与文件IO的函数使用方式相同,
3. 无名管道读写注意点:
1)当管道中无数据时,读操作会阻塞。
2)无名管道只能实现以下一种方式:
方式1:父进程->子进程:父进程对自己的fd[1]执行写操作,数据流入管道内,然后子进程对自己的fd[0]执行读操作,得到管道内数据
方式2:子进程->父进程:子进程对自己的fd[1]执行写操作,数据流入管道内,然后父进程对自己的fd[0]执行读操作,得到管道内数据
3)只有在管道的读端存在时,向管道中写入数据才有意义。否则,向管道中写入数据的进程将收到内核传来的SIGPIPE信号(通常Broken pipe错误)。
示例程序:
/*************************************************************************
@Author: wanghao
@Created Time : Wed 23 May 2018 03:27:53 AMPDT
@File Name: pipe_demo.c
@Description:
************************************************************************/
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
int main(void)
{
intfd[2];
if(pipe(fd)< 0){
perror("pipeerror");
exit(1);
}
pid_tpid;
if((pid= fork())<0){
perror("forkerror");
exit(1);
}elseif(pid > 0){
close(fd[0]);
intstart =1,end =100;
if(write(fd[1],&start,sizeof(int))!= sizeof(int)){
perror("writeerror");
exit(1);
}
if(write(fd[1],&end,sizeof(int))!= sizeof(int)){
perror("writeerror");
exit(1);
}
close(fd[1]);
}else{
close(fd[1]);
intstart,end;
if(read(fd[0],&start,sizeof(int))<0){
perror("readerror");
exit(1);
}
if(read(fd[0],&end,sizeof(int))<0){
perror("readerror");
exit(1);
}
close(fd[0]);
printf("childprocess read start: %d, end: %d\n",start,end);
}
exit(0);
}
二、有名管道fifo
1. FIFO特点
1)无名管道只能用于具有亲缘关系的进程之间
2)有名管道可以使不相关的两个进程互相通信。有名管道可以通过路径来指出,并且在文件系统中可见。
3)进程通过文件IO来操作有名管道。
4)有名管道遵循先进先出规则
5)不支持如lseek操作
2.创建fifo
函数mkfifo()
所需头文件:#include<sys/types.h>
#include<sys/stat.h>
函数原型:int mkfifo(const char *pathname,mode_t mode)
函数参数:pathname 要创建的有名管道的路径名与文件名
mode 创建的有名管道的文件权限码,通常用八进制数字表示
函数返回值:成功:0
失败:-1
注:也可以使用mkfifo命令创建有名管道文件
创建fifo失败原因:
EACCESS 参数filename所指定的目录路径无可执行的权限
EEXIST 参数filename所指定的文件已存在
ENAMETOOLONG 参数filename路径名称太长
ENOENT 参数filename包含的目录不存在
ENOSPC 文件系统的剩余空间不足
EROFS 参数filename指定的文件存在于只读文件系统内
示例代码:
1. 首先通过mkfifo fifo创建fifo文件,当然也可以通过mkfifo函数创建
2. 读fifo文件代码如下:
/*************************************************************************
@Author: wanghao
@Created Time : Wed 23 May 2018 03:47:48 AMPDT
@File Name: fifo_read_demo.c
@Description:
************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <string.h>
int main(int argc,char *argv[])
{
if(argc<2){
printf("usage:%s fifo\n",argv[0]);
exit(1);
}
printf("openfifo read...\n");
intfd = open(argv[1],O_RDONLY);
if(fd< 0){
perror("openerror");
exit(1);
}else{
printf("openfile success:%d\n",fd);
}
charbuf[512];
memset(buf,0,sizeof(buf));
while((read(fd,buf,sizeof(buf)))< 0){
perror("readerror");
}
printf("%s\n",buf);
close(fd);
return0;
}
3. 写fifo文件代码如下:
/*************************************************************************
@Author: wanghao
@Created Time : Wed 23 May 2018 03:49:15 AMPDT
@File Name: fifo_write_demo.c
@Description:
************************************************************************/
#include <unistd.h>
#include <memory.h>
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
int main(int argc,char *argv[0])
{
if(argc< 2){
printf("usage:%s fifo\n",argv[0]);
exit(1);
}
printf("openfifo write...\n");
intfd = open(argv[1],O_WRONLY);
if(fd< 0){
perror("openerror");
exit(1);
}else{
printf("openfifo success: %d\n",fd);
}
char*s = "1234567890";
size_tsize = strlen(s);
if(write(fd,s,size)!= size){
perror("writeerror");
}
close(fd);
exit(0);
}