管道应用的一个限制就是只能在具有共同祖先(具有亲缘关系)的进程间通信。 如果我们想在不相关的进程之间交换数据,可以使用FIFO文件来做这项工作,它经常被称为命名管道
命名管道的本质是一个特殊类型的文件,但它不会存储数据,只在内存中维护一个缓冲区,进行先进先出(FIFO)的数据传输
使用 mkfifo() 或 mknod() 在文件系统中创建一个特殊文件。
命名管道可以从命令行上创建,命令行方法是使用下面这个命令
mkfifo filename
p开头为管道文件
这里的读和写都是阻塞的,管道文件大小一直都是0,因为命名管道数据存储在内存中
命名管道也可以从程序里创建,相关函数:
int mkfifo(const char *filename,mode_t mode);
代码实现:首先完成管道生命周期的管理:
namedPipe.hpp文件,提供管道创建和关闭的函数:
#pragma once
#include<iostream>
#include <sys/types.h>
#include <sys/stat.h>
#include<string>
#include<cerrno>
#include<cstdio>
#include<unistd.h>
using namespace std;
const string comm_path ="./myfifo";
int CreateNamedPipe(const string & path)
{
int res =mkfifo(path.c_str(),0666);
if(res!=0)
{
perror("mkfifo");
}
return res;
}
int RemoveNamedPipe(const string & path)
{
int res =unlink(path.c_str());
if(res!=0)
{
perror("unlink");
}
return res;
}
server.cc:
#include"namedPipe.hpp"
int main()
{
CreateNamedPipe(comm_path);
RemoveNamedPipe(comm_path);
return 0;
}
我们这里创建了两个文件,server.cc和client.cc,一定有一个文件来完成管道的创建和删除,这里生成可执行程序就是两个毫无关系的进程
这里可以对上面方法进行封装:
class NamedPipe
{
public:
NamedPipe(const string &path) : _fifo_path(path)
{
int res = mkfifo(path.c_str(), 0666);
if (res != 0)
{
perror("mkfifo");
}
}
~NamedPipe()
{
int res = unlink(_fifo_path.c_str());
if (res != 0)
{
perror("unlink");
}
}
private:
const string _fifo_path;
};
我的主函数直接构建对象即可:
NamedPipe myfifo(comm_path);
管道会自动释放
这里继续在类里面添加其他功能
const string comm_path = "./myfifo";
#define DefaultFd -1
#define Creater 1
#define User 2
#define Read O_RDONLY
#define Write O_WRONLY
class NamedPipe
{
private:
bool OpenNamedPipe(int mode)
{
_fd = open(_fifo_path.c_str(), mode);
if (_fd < 0)
return false;
return true;
}
public:
NamedPipe(const string &path, int who) : _fifo_path(path), _id(who), _fd(DefaultFd)
{
if (_id == Creater)
{
int res = mkfifo(path.c_str(), 0666);
if (res != 0)
{
perror("mkfifo");
}
}
}
bool OpenForRead()
{
OpenNamedPipe(Read);
}
bool OpenForWrite()
{
OpenNamedPipe(Write);
}
~NamedPipe()
{
if (_id == Creater)
{
int res = unlink(_fifo_path.c_str());
if (res != 0)
{
perror("unlink");
}
}
if(_fd!=DefaultFd) close(_fd);
}
private:
const string _fifo_path;
int _id;
int _fd;
};
隐藏打开文件的函数操作,定义宏常量Read和Write两种打开文件方式的mode,初始化传递执行者,是创建者还是使用者来决定构建的时候是否还要再进行管道文件创造
int ReadNamedPipe(string * out)//输出型参数,输入型const& 输入输出型&
{
char buffer[BaseSize];
int n = read(_fd,buffer,sizeof(buffer));
if(n>0)
{
buffer[n]=0;
*out = buffer;
}
return n;
}
int WriteNamedPipe(const string & in)
{
write(_fd,in.c_str(),in.size());
}