目录
一、命名管道的定义即功能
1.1创建命名管道
1.2匿名管道和命名管道的区别
1.3命名管道的打开规则
1.4系统调用unlink
二、进程间命名管道的创建及使用
2.1Comm.hhp
2.2PipeServer.cc
2.3PipeClient.cc
一、命名管道的定义即功能
匿名管道只能通过fork的方式来实现父子两个进程之间的通信,而命名管道则是可以让仁义两个进程间实现通信 ,其底层原理为让两个进程打开同一个文件,一个读一个写从而实现通信的功能,当然此文件并不是真的在磁盘中创建了一个文件而是在内存中开辟了一块缓冲区而已。
而打开同一个文件就需要找到文件,即文件的路径+文件名。而通过文件名加路径的管道就是命名管道。
1.1创建命名管道
命名管道可以从命令行上创建,命令行方法是使用下面这个命令:
$ mkfifo filename
命名管道也可以从程序里创建,相关函数有:
int mkfifo(const char *filename,mode_t mode);
此时就可以看到一个开头为p的管道文件。此时就可以打开两个窗口,一边往里写一边往里读。
而系统调用的mkfifo需要两个参数pathname表示要创建文件的文件名,mode则是默认权限。
int main(int argc, char *argv[])
{
mkfifo("p2", 0644);
return 0;
}
1.2匿名管道和命名管道的区别
1.3命名管道的打开规则
1.4系统调用unlink
如果想要在代码中删除文件可以调用unlink来进行删除操作。 0返回表示成功,-1表示失败,错误码被设置。
二、进程间命名管道的创建及使用
2.1Comm.hhp
Comm.hpp包含了文件操作所需要的头文件以及常用头文件,包含了Fifo的管道类,可以实现管道的创建及命名,以及在进程结束时及时调用析构函数来对管道进行清理回收。
#ifndef __COMM_HPP__
#define __COMM_HPP__
//头文件
#include <cstring>
#include <string>
#include <cerrno>
#include <iostream>
//调用fifo所需的头文件+opean用到的头文件
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>//open
//调用unlink对管道进行析构的头文件
#include <unistd.h>
//define
#define Mode 0666
#define Path "./fifo"
using namespace std;
class Fifo
{
public:
Fifo(const string &path):_path(path)//创建有名管道
{
umask(0);
int n=mkfifo(_path.c_str(),Mode);
if(n==0)
{
cout<<"mkfifo sucess"<<endl;
}
else
{
cerr<<"mkfifo failed,errno: "<<errno<<",errstring: "<<strerror(errno)<<endl;
}
}
~Fifo()
{
int n=unlink(_path.c_str());//删除管道
if(n==0)
{
cout<<"remove fifo file "<<_path<<"sucess"<<endl;
}
else
{
cerr<<"remove failed,errno: "<<errno<<",errstring: "<<strerror(errno)<<endl;
}
}
private:
string _path;//有名管道的文件路径+文件名
};
#endif
2.2PipeServer.cc
服务器端负责创建管道并以读方式open打开:
pipeserver负责创建有名管道fifo并且以读方式进行打开,打开后会发出打开成功的信号,然后等待pipeclient往管道内部写入内容后将其读出以此来达到进程间通信的效果,如果client输入quit则一同退出。
pipeserver就类似于服务器一类的角色,负责创建通信工具和用于接收内容并进行反馈。
#include "Comm.hpp"
#include <unistd.h>
int main()
{
Fifo fifo(Path);//定义管道文件fifo
int rfd=open(Path,O_RDONLY);
if(rfd<0)
{
cerr<<"open failed,errno: "<<errno<<",errstring: "<<strerror(errno)<<std::endl;
return 1;
}
//如果我们的写端没有打开,先读端打开,open就会阻塞,直到把写端打开,读open才会返回
cout<<"open sucess"<<endl;
char buffer[1024];
while(true)
{
ssize_t n=read(rfd,buffer,sizeof(buffer)-1);//文件读的时候不需要考虑/0所以sizeof-1
if(n>0)
{
buffer[n]=0;//将最后一位变为0
cout<<"client say: "<<buffer<<endl;
}
else if(n==0)
{
cout<<"client quit,me too bye bye"<<std::endl;
break;
}
else
{
cerr<<"read failed,errno: "<<errno<<",errstring: "<<strerror(errno)<<endl;
break;
}
}
close(rfd);
return 0;
}
2.3PipeClient.cc
pipeclient则就是供用户进行使用的端口,使用端以写方式打开管道文件,并且负责向管道内部写入数据以及内容,然后由服务器进行读取。
#include "Comm.hpp"
int main()
{
int wfd=open(Path,O_WRONLY);
if(wfd<0)
{
cerr<<"open failed,errno: "<<errno<<",errstring"<<strerror(errno)<<std::endl;
return 1;
}
string inbuffer;
while(true)
{
cout<<"Please Enter Your Message#";
getline(cin,inbuffer);
if(inbuffer=="quit") break;
ssize_t n=write(wfd,inbuffer.c_str(),inbuffer.size());
if(n<0)
{
cerr<<"write failed,errno: "<<errno<<",errstring: "<<strerror(errno)<<std::endl;
break;
}
}
close(wfd);
return 0;
}