管道简介:
管道是进程之间通信的一种方式,就相当于是两个进程之间有一条地道,可以通过地道来传递信息;
管道位于进程的地址空间之外;管道分为匿名管道和命名管道两种;
匿名管道是由pipe来创建的,命名管道是由mkfifo来创建的;
#include
int pipe(int pipefd[2]);返回两个描述符:pipefd[0]是管道的读端,pipefd[1]是管道的写端;
#include
#include
int mkfifo(const char *pathname, mode_t mode)创建命名管道成功返回0;参数是一个pathname是创建的FIFO管道文件的名字;mode用户权限是标识位,比如是0644;
创建了一个管道文件之后,要用它和其它进程通信的时候需要再打开该文件open;
命名管道的打开规则
如果当前打开操作是为读而打开FIFO时
1:O_NONBLOCK disable:阻塞直到有相应进程为写而打开该FIFO
2:O_NONBLOCK enable:立刻返回成功
如果当前打开操作是为写而打开FIFO时
1:O_NONBLOCK disable:阻塞直到有相应进程为读而打开该FIFO
2:O_NONBLOCK enable:立刻返回失败,错误码为ENXIO
//outfd = open("fifop", O_WRONLY | O_NONBLOCK);//非阻塞写
outfd = open("fifop", O_WRONLY ); //阻塞模式
例如:
1:一个进程打开命名管道写,默认是阻塞的方式打开;如果该管道没有另外的进程打开读,则该进程阻塞在写打开,直到有进程读打开;
2:一个进程打开命名管道读,默认是阻塞的方式打开;如果该管道没有另外的进程打开写,则该进程阻塞在读打开,直到有进程写打开;
一般以阻塞方式打开,如果是以非阻塞方式打开的话,每次从该文件读取数据的时候会立刻返回,哪怕是没有数据;
命名管道和匿名管道区别:
1:管道应用的一个限制就是只能在具有共同祖先(具有亲缘关系)的进程间通信。
2:如果我们想在不相关的进程之间交换数据,可以使用FIFO文件来做这项工作,它经常被称为命名管道。
3:命名管道是一种特殊类型的文件;
管道可以在父子进程之间传递数据
管道可以在父子进程之间传递数据,利用的是fork调用之后两个管道文件描述符pipefd[0]和pipefd[1]都保持打开。这样就可以实现父进程通过管道向子进程传递数据,或者子进程通过管道向父进程传递数据。
如果是想双向传输数据的话,可以创建两个管道。也可以通过socketpair创建一个全双工的管道。
例子1:父进程通过匿名和子进程通信,父进程向匿名管道写入数据,子进程从匿名管道读出数据并输出到标准输出上面
/*************************************************************************
> File Name: pipe1.cpp
> Author:
> Mail:
> Created Time: 2015年12月20日 星期日 19时48分57秒
************************************************************************/
#include
#include
#include
#include
#include
#include
#include
using namespace std;
/*
1:父进程创建一个管道, 0-read, 1-write
2:父进程创建一个子进程
3:让父进程向管道中写入信息,子进程从管道读取信息;从标准输入写入到管道中
4:子进程将读取的信息输出到标准输出上面
*/
int main()
{
int pipefd[2];
char buff[1024];
memset(buff, 0, 1024);
int ret = pipe(pipefd);
if(ret != 0){
cerr << "pipe error..." << endl;
exit(-1);
}
pid_t pid = fork();
if(pid < 0){
cerr << "fork error..." << endl;
exit(-1);
}
else if(pid == 0){
//关闭管道的写端
close(pipefd[1]);
int ret = 0;
cout << "This is child process...." << endl;
while(1){
ret = read(pipefd[0], (void *)buff, 1024);
if(ret == 0){
cout << "end of read.." << endl;
exit(0);
}
cout << "child read: ";
cout << buff << endl;
memset(buff, 0, 1024);
}
close(pipefd[0]);
}
else if(pid > 0){
close(pipefd[0]);
cout << "This is parent process...." << endl;
while(cin.getline(buff, 1024)){
cout << "parent write: ";
cout << buff << endl;
write(pipefd[1], buff, 1024);
memset(buff, 0, 1024);
}
close(pipefd[1]);
wait(NULL);
}
exit(0);
}
例子2:
进程1创建命名管道myfifo,并以阻塞方式写打开,进程1从标准输入获得数据并写入到命名管道中;
进程2以阻塞方式读打开该命名管道文件myfifo,进程2从该命名管道中读取数据并输出到标准输出上;
进程1:write_fifo.cpp
/*************************************************************************
> File Name: write_fifo.cpp
> Author:
> Mail:
> Created Time: 2015年12月20日 星期日 20时53分29秒
************************************************************************/
#include
#include
#include
#include
#include
#include
#include
using namespace std;
/*
1:创建命名管道
2:从标准输入输入内容到buffer中
3:打开命名管道,将buffer中的内容写入到命名管道中
*/
int main()
{
int ret = mkfifo("myfifo", 0666);
if(ret < 0){
cerr << "mkfifo error..." << endl;
exit(-1);
}
char buff[1024];
memset(buff, 0, 1024);
int wrfd;
cout << "wating for another process open the myfifo to reading..."<< endl;
wrfd = open("myfifo", O_WRONLY);
if(wrfd == -1){
cerr << "open error..." << endl;
exit(-1);
}
pid_t pid = getpid();
cout << "process " << pid << " write: ";
while(cin.getline(buff, 1024)){
write(wrfd, buff, strlen(buff));
memset(buff, 0, 1024);
cout << "process " << pid << " write: ";
}
close(wrfd);
exit(0);
}进程2:read_fifo.cpp
/*************************************************************************
> File Name: write_fifo.cpp
> Author:
> Mail:
> Created Time: 2015年12月20日 星期日 20时53分29秒
************************************************************************/
#include
#include
#include
#include
#include
#include
#include
using namespace std;
/*
1:创建命名管道
2:从标准输入输入内容到buffer中
3:打开命名管道,将buffer中的内容写入到命名管道中
*/
int main()
{
char buff[1024];
memset(buff, 0, 1024);
int rdfd;
int ret = 0;
rdfd = open("myfifo", O_RDONLY);
if(rdfd < 0){
cout << "open error..." << endl;
exit(-1);
}
cout << "waiting for reading...\n";
while(1){
ret = read(rdfd, buff, 1024);
if(ret == 0){
cerr << "end of read..." << endl;
break;
}
cout << "process "<< getpid() << " read: " << buff << endl;
memset(buff, 0, 1024);
}
close(rdfd);
exit(0);
}
下面图中的myfifo文件就是创建的命名管道,可以看到它的文件类型为p开头;