户外旅游网站模板,合肥建设工程交易网站,成都工商注册咨询电话,达内网站开发目录
3、解决遗留BUG -- 边关闭信道边回收进程
1#xff09;解决方案
2#xff09;两种方法相比较
4、命名管道
1#xff09;理解命名管道
2#xff09;创建命名管道
a. 命令行指令
b. 系统调用方法
3#xff09;代码实现命名管道
构建类进行封装命名管道#…目录
3、解决遗留BUG -- 边关闭信道边回收进程
1解决方案
2两种方法相比较
4、命名管道
1理解命名管道
2创建命名管道
a. 命令行指令
b. 系统调用方法
3代码实现命名管道
构建类进行封装命名管道
构造和析构
读取管道、写入管道
server.cc 读端
client.cc写端
效果
4疑点解决
写端未来读端open调用阻塞
读端关闭写端继续写入
5完整代码
namedPipe.hpp:
server.cc:
client.cc: 3、解决遗留BUG -- 边关闭信道边回收进程
1解决方案 我们仍然想用上述方法进行管道和子进程的回收
-- 则需要解决子进程所继承的父进程遗留的多余wfd我们在每次创建子进程时遍历所有之前的信道关闭掉wfd即可就不会出现多个wfd指向一个管道 2两种方法相比较
退一个回收一个 先全部退出再进行等待回收 4、命名管道
1理解命名管道 命名该管道有名字因为该文件有路径有路径必有文件名 管道依旧是一个内存级的基于文件进行通信的通信方案 属性、操作、文件内核缓冲区同一个文件的都是差不多的因此不用再创建一份操作系统不做浪费时间和空间的事情 我们怎么保证两个毫不相关的进程打开了同一个文件呢 每一个文件都有文件路径(唯一性) 2创建命名管道
a. 命令行指令 一个进程echo向命名管道里面输入数据 一个进程cat向命名管道里面读取数据 这样就实现了两个毫不相关的进行之间的通信 创建了三个窗口一个一直向管道输入一个一直读取一个手动检测管道大小 但是我们可以看到管道文件myfifo的大小一直显示0 因为 FIFO0 文件虽存在于文件系统中但其内容都存放在内存里不会将通信数据刷新到磁盘中所以在磁盘上显示的文件大小始终为0 b. 系统调用方法 使用mkfifo即可创建管道文件 使用unlink即可删除一个管道文件当然rm也可以删除 3代码实现命名管道 创建两个.cc文件分别模拟两个进程一个进行发送一个进行读取 通过一个CreateNamedPipe和一个RemoveNamedPipe就可以实现对管道生命周期的管理 当然我们管理管道的声明周期时肯定是将创建和删除交给同一个文件去做比较好因为它清楚什么时候去删除合适 这里我们让发送的那方去管理管道的生命周期 构建类进行封装命名管道
我们需要创建管道的路径共同路径、创建管道的身份、管道的文件描述符
class NamedPipe
{
private:const std::string _fifo_path;int _id;int _fd;
};
构造和析构
class NamedPipe
{
public:NamedPipe(const std::string path, int who): _fifo_path(path), _id(who), _fd(DefaultFd){if (_id Creater){int res mkfifo(_fifo_path.c_str(), 0666);if (res ! 0){perror(mkfifo);}std::cout creater create named pipe std::endl;}}~NamedPipe(){sleep(5);if (_id Creater){int res unlink(_fifo_path.c_str());if (res ! 0){perror(unlink);}std::cout creater remove named pipe std::endl;}if(_fd ! DefaultFd) close(_fd);}private:const std::string _fifo_path;int _id;int _fd;
};
读取管道、写入管道
class NamedPipe
{
private:bool OpenNamedPipe(int mode){_fd open(_fifo_path.c_str(), mode);if(_fd 0) return false;return true;}public:NamedPipe(const std::string path, int who): _fifo_path(path), _id(who), _fd(DefaultFd){if (_id Creater){int res mkfifo(_fifo_path.c_str(), 0666);if (res ! 0){perror(mkfifo);}std::cout creater create named pipe std::endl;}}bool OpenForRead(){return OpenNamedPipe(Read);}bool OpenForWrite(){return OpenNamedPipe(Write);}int ReadNamedPipe(std::string *out){char buffer[BaseSize];int n read(_fd, buffer, sizeof(buffer));if(n 0){buffer[n] 0; // \0*out buffer;}return n;}int WriteNamedPipe(const std::string in){return write(_fd, in.c_str(), in.size());}~NamedPipe(){sleep(5);if (_id Creater){int res unlink(_fifo_path.c_str());if (res ! 0){perror(unlink);}std::cout creater remove named pipe std::endl;}if(_fd ! DefaultFd) close(_fd);}private:const std::string _fifo_path;int _id;int _fd;
};
server.cc 读端
#include namedPipe.hpp// server -- read : 管理命名管道的整个生命周期
int main()
{NamedPipe fifo(comm_path, Creater);// 对于读端而言如果我们打开了文件但是写还没有来我们会阻塞在open调中直到对方打开// -- 一种变向的进程同步if (fifo.OpenForRead()){std::cout Server open named pipe done std::endl; // 为了检测阻塞sleep(3);while (true){std::string message;int n fifo.ReadNamedPipe(message);if (n 0) // 正常接收{std::cout Client Say message std::endl;}else if(n 0) // 即写端关闭{std::cout Client quit, Server too! std::endl;break;}else {std::cout fifo.ReadNamedPipe Error! std::endl;break;}}}return 0;
}
client.cc写端
#include namedPipe.hpp// client -- write
int main()
{NamedPipe fifo(comm_path, User); // 以非创建身份实例化if(fifo.OpenForWrite()){std::cout client open named pipe done std::endl;while(true){std::cout Please Enter ;std::string message;std::getline(std::cin, message);fifo.WriteNamedPipe(message);}}return 0;
}
效果 实现了两个进程无父子关系之间的通信
4疑点解决
写端未来读端open调用阻塞 读端关闭写端继续写入 5完整代码
namedPipe.hpp:
#pragma once#include iostream
#include string
#include cstdio
#include cerrno
#include unistd.h
#include sys/types.h
#include sys/stat.h
#include fcntl.hconst std::string comm_path ./myfifo;#define DefaultFd -1
#define Creater 1
#define User 2
#define Read O_RDONLY
#define Write O_WRONLY
#define BaseSize 4096class NamedPipe
{
private:bool OpenNamedPipe(int mode){_fd open(_fifo_path.c_str(), mode);if(_fd 0) return false;return true;}public:NamedPipe(const std::string path, int who): _fifo_path(path), _id(who), _fd(DefaultFd){if (_id Creater){int res mkfifo(_fifo_path.c_str(), 0666);if (res ! 0){perror(mkfifo);}std::cout creater create named pipe std::endl;}}bool OpenForRead(){return OpenNamedPipe(Read);}bool OpenForWrite(){return OpenNamedPipe(Write);}int ReadNamedPipe(std::string *out){char buffer[BaseSize];int n read(_fd, buffer, sizeof(buffer));if(n 0){buffer[n] 0; // \0*out buffer;}return n;}int WriteNamedPipe(const std::string in){return write(_fd, in.c_str(), in.size());}~NamedPipe(){sleep(5);if (_id Creater){int res unlink(_fifo_path.c_str());if (res ! 0){perror(unlink);}std::cout creater remove named pipe std::endl;}if(_fd ! DefaultFd) close(_fd);}private:const std::string _fifo_path;int _id;int _fd;
};
server.cc:
#include namedPipe.hpp// server -- read : 管理命名管道的整个生命周期
int main()
{NamedPipe fifo(comm_path, Creater);// 对于读端而言如果我们打开了文件但是写还没有来我们会阻塞在open调中直到对方打开// -- 一种变向的进程同步if (fifo.OpenForRead()){std::cout Server open named pipe done std::endl;sleep(3);while (true){std::string message;int n fifo.ReadNamedPipe(message);if (n 0){std::cout Client Say message std::endl;}else if(n 0){std::cout Client quit, Server too! std::endl;break;}else{std::cout fifo.ReadNamedPipe Error! std::endl;break;}}}return 0;
}
client.cc:
#include namedPipe.hpp// client -- write
int main()
{NamedPipe fifo(comm_path, User);if(fifo.OpenForWrite()){std::cout client open named pipe done std::endl;while(true){std::cout Please Enter ;std::string message;std::getline(std::cin, message);fifo.WriteNamedPipe(message);}}return 0;
}