您的位置:首页 > 运维架构 > Linux

linux进程间管道通信pipe与fifo

2017-09-13 20:47 639 查看
进程间通信的方式有很多种,管道通信就是其中一种,所谓管道通信就是通信流程类似管道流水具有单向性,数据只能从一个方向流向另一个方向。不能反向传输。
管道通信又分为无名管道通信、有名管道通信。无名管道只能用于父子进程间通信、自身通信(不常用意义不大),相互独立的进程不能通信,无名管道通信示意如下:



实际管道1、2的角色是由内核充当的。

pipe函数格式如下

#include <unistd.h>
int pipe(int pipefd[2]);
函数返回值:管道创建成功返回0 失败返回 -1

函数的参数:数量为2的整形数组

规定无名管道通信 fd[1]数据写入端  fd[0]数据读取端

举例说明无名管道的用法,其实很简单:

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/wait.h>
#include <stdlib.h>
int main(int argc,char *argv[])
{
int fd[2];  //定义管道数组
pid_t pid,pd;      //定义进程ID
char buffer[100];  //定义管道数据缓冲区
if(pipe(fd)<0)
printf("creat pipe failed!!\r\n");   //管道创建失败

pid=fork();                    //创建子进程
if(pid<0)
{
printf("creat fork failed");   //创建进程失败
}else if(pid==0)
{
close(fd[1]);         //子进程 关闭fd[1] 只用于接收数据
printf("this is %d child process wait data now!!\r\n",getpid());  //打印子进程进程号 显示等待数据
read(fd[0],buffer,50);    //管道读取数据存放在buffer中
printf("read string is %s\r\n",buffer);   //打印读取的数据
close(fd[0]);                              //关闭fd[0]
}else if(pid>0)
{
close(fd[0]);                       //父进程关闭fd[0]  用于穿送数据
printf("this is father process!!\r\n");   //打印身份标识  这是父进程
sleep(5);                              //睡眠5秒钟  观察子进程状态
write(fd[1],argv[1],10);            //向管道写入数据 数据为传入的第二个参数
printf("wait child exit\r\n");       //等待子进程退出
pd= wait(NULL);
printf("child process %d is exit\r\n",pd);  //子进程退出 打印子进程进程号
close(fd[1]);                     //关闭管道写入口
}
exit(0);             //进程结束
}
执行以上代码结果:

[root@localhost pipe]# gcc -o test test.c
[root@localhost pipe]# ls
test  test.c
[root@localhost pipe]# ./test 123456
this is father process!!
this is 3199 child process wait data now!!
wait child exit
read string is 123456
child process 3199 is exit
可以看出父进程先执行,随后进入休眠状态,子进程开始执行。等待管道数据,父进程苏醒以后,向管道写入数据,随后等待子进程结束,子进程读取管道信息打印出来之后,结束进程。父进程收到子进程结束的消息。父进程打印结束的子进程进程号,结束自身。程序运行结束。

结果表明如果管道为空,读取管道的进程将会阻塞,不再继续执行直到数据的来临。(可以通过运行./test 不向函数传入参数实验,程序将卡死)。

那么有读取空管道而进程不阻塞的办法么?其实是有的在linux发布的2.6.xx版本之后就加入了pipe2()函数,与pipe不同的是,pipe2函数加入了第二个参数,参数填写O_NOBLOCK之后,进程在读取空管道或写入非空管道时将不会阻塞进程。这里不在演示。

下面介绍有名管道fifo,fifo的优势在于它可以在不同进程间通讯,实质上fifo是一种特殊的文件,fifo一旦创建就可以用open函数打开它,一般的文件操作函数(close、write、read)都可以用于fifo,相关进程通过访问该文件,通过读取或写入相应数据达到进程间通讯的目的。

创建有名管道的函数结构如下:

#include <sys/types.h>
#include <sys/stat.h>
int mkfifo(const char *pathname,,mode_t mode);


当管道创建失败返回值小于0。

参数一是所创建fifo的名称可以跟路径。
参数二是fifo的参数:其中最重要的是 0_CREAT 和O_EXCL这两个参数,这两个参数同时使用,O_CREAT创建fifo,O_EXCL创建管道失败返回错误。

同无名管道一样,访问有名管道无法满足进程要求时,进程将会阻塞,如试图读取空的fifo。如果想避免这种状况在打开fifo加入O_NONBLOCK这个参数即可,当访问无法满足要求时,进程不阻塞,但立刻出错返回,errno是ENXIO。

下面写两个例程说明一下fifo的用法。为什么是两个?因为fifo可以用于不同进程。所以这里利用两个例程来说明。

例程1:创建并读取fifo 打开fifo时加入O_NONBLOCK即使读取空fifo进程不会阻塞。

#include <stdio.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/types.h>
#include <stdlib.h>
#include <string.h>
#define MYFIFO "/zhangchao/fifo/fifotest" //定义管道路径 名称

int main(void)
{
int fd; //定义文件描述符
char buf[100]; //读取数据缓存区
if(mkfifo(MYFIFO,O_CREAT | O_EXCL)<0) //创建fifo管道 如果没有就创建 创建失败返回错误
{
printf("创建FIFO失败\r\n");
return 0;
}
printf("等待读取管道数据\r\n");
fd=open(MYFIFO,O_RDONLY | O_NONBLOCK);//打开fifo管道 只读打开 没有数据不等待不会导致进程阻塞
printf("文件描述符:%d\r\n",fd);
while(1)
{
memset(buf,0,sizeof(buf)); //清空缓存区
if(read(fd,buf,100)<0) //没有数据
printf("管道没有数据\r\n");
printf("读出管道数据为:%s\r\n",buf);
sleep(1);
}
close(fd);
return 0;
}
例程2:写fifo
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#define MYFIFO "/zhangchao/fifo/fifotest"
int main(void)
{
int fd;
char buf[]="123456789";
fd=open(MYFIFO,O_WRONLY|O_NONBLOCK);
if(write(fd,buf,100)<0)
{
printf("管道有数据没有被读走\r\n");

}
close(fd); return 0; }


编译两个例程:

[root@localhost fifo]# gcc -o fifo1 fiforead.c
[root@localhost fifo]# gcc -o fifo2 fifowrite.c
[root@localhost fifo]# ls
fifo1 fifo2 fiforead.c fifowrite.c
[root@localhost fifo]# ./fifo1
等待读取管道数据
文件描述符:3
读出管道数据为:
读出管道数据为:
读出管道数据为:
读出管道数据为:
读出管道数据为:
读出管道数据为:
读出管道数据为:123456789
读出管道数据为:
读出管道数据为:
读出管道数据为:
读出管道数据为:
读出管道数据为:在另外一个终端执行
[root@localhost fifo]# ./fifo2

在文件目录可以查看一下文件情况

[root@localhost fifo]# ls
fifo1 fifo2 fiforead.c fifotest fifowrite.c
[root@localhost fifo]# ls -l fifotest
p-wx------. 1 root root 0 9月 15 22:32 fifotest程序运行之后在文件目录多了 fifotest 文件,查看它的属性属于以p开头的管道文件,更加可以说明fifo有名管道其实就是一种特殊的文件。
如果使用命令行界面,切换终端的方式为ctrl+alt+F(1~6);

代码运行平台CentOS6.3
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  linux pipe fifo