命名管道
实现目的
实现一个写端进程负责发送数据,运行多个读端进程,并且写端进程与每个读端进程都有独立的命名管道
写端进程可以随机向某个管道中写入数据后,管道对应的读端将数据读取输出
思路
- 编写一个头文件,定义所有需要创建的命名管道的文件名,并将所有文件名集合到一个数组中
- 定义创建命名管道文件的函数
- 定义删除明明管道文件的函数
- 编写写端程序,一次性在当前目录下将所有的命名管道文件创建,并记录所有命名管道的fd到一个数组中,将所有管道文件打开
- 编写向管道文件中写入的方法,首先先将写入的字符串保存,随机生成一个下标,知道到该下标对应的fd,并往该fd对应的管道文件中写入
- 编写全部读端程序,每个读端程序对应一个管道文件,并将管道文件打开
- 编写读端读取数据的方法
- 在每一个读端程序中加入删除管道文件的步骤,当写端退出时,读端也会随着退出,退出关闭fd后将管道文件删除
- 需要注意,以下代码示例为写端创建管道文件,因此要先运行写端程序。
NAME_PIPE.hpp
#include<iostream> #include<unistd.h> #include<string> #include<cstring> #include<sys/types.h> #include<sys/stat.h> #include<cassert> #include<errno.h> #include<vector> #include<fcntl.h> #include<ctime> //宏定义管道名字 #define NAME_PIPE_1 "./NAME_PIPE_1" #define NAME_PIPE_2 "./NAME_PIPE_2" #define NAME_PIPE_3 "./NAME_PIPE_3" #define NAME_PIPE_4 "./NAME_PIPE_4" //将管道名字保存 std::vector<std::string> NameGroup({NAME_PIPE_1, NAME_PIPE_2, NAME_PIPE_3, NAME_PIPE_4}); //创建管道函数 bool CreatPipe(const std::string& path){ umask(0); int n = mkfifo(path.c_str(), 0666); if(n == 0) return true; else{ std::cout << "管道创建失败:" << strerror(errno) << std::endl; return false; } } //删除管道函数 void RemovePipe(const std::string& path){ assert(unlink(path.c_str()) == 0); }
WProc.cc
#include"NAME_PIPE.hpp" int main(){ srand(time(nullptr)); std::vector<int> Fdgroup; //创建所有的管道文件 for(int i = 0; i < NameGroup.size(); ++i) assert(CreatPipe(NameGroup[i])); //打开所有的管道文件,并将所有的管道文件fd保存 for(int i = 0; i < NameGroup.size(); ++i){ int fd = open(NameGroup[i].c_str(), O_WRONLY); if(fd < 0) return 1; Fdgroup.push_back(fd); } std::string str; while(1){ //随机生成一个下标,往该下标的管道文件中写入 int i = rand() % Fdgroup.size(); std::cout << "开始写入:"; getline(std::cin, str); int s = write(Fdgroup[i], str.c_str(), strlen(str.c_str())); } //关闭所有管道文件 for(int i = 0; i < Fdgroup.size(); ++i) close(Fdgroup[i]); return 0; }
RProc1.cc
#include"NAME_PIPE.hpp" int main(){ //打开管道文件只读 int fd = open(NAME_PIPE_1, O_RDONLY); assert(fd > 0); //阻塞着随时等待管道文件中有数据,一有数据立刻读取 while(1){ char buff[1024]; int s = read(fd, buff, sizeof(buff) - 1); if(s > 0) buff[s] = 0; else break; std::cout << "RProc1 read : " << buff << std::endl; } close(fd); //删除对应的管道文件 RemovePipe(NAME_PIPE_1); return 0; }
RProc2.cc
#include"NAME_PIPE.hpp" int main(){ int fd = open(NAME_PIPE_2, O_RDONLY); assert(fd > 0); while(1){ char buff[1024]; int s = read(fd, buff, sizeof(buff) - 1); if(s > 0) buff[s] = 0; else break; std::cout << "RProc2 read : " << buff << std::endl; } close(fd); RemovePipe(NAME_PIPE_2); return 0; }
RProc3.cc
#include"NAME_PIPE.hpp" int main(){ int fd = open(NAME_PIPE_3, O_RDONLY); assert(fd > 0); while(1){ char buff[1024]; int s = read(fd, buff, sizeof(buff) - 1); if(s > 0) buff[s] = 0; else break; std::cout << "RProc3 read : " << buff << std::endl; } close(fd); RemovePipe(NAME_PIPE_3); return 0; }
RProc4.cc
#include"NAME_PIPE.hpp" int main(){ int fd = open(NAME_PIPE_4, O_RDONLY); assert(fd > 0); while(1){ char buff[1024]; int s = read(fd, buff, sizeof(buff) - 1); if(s > 0) buff[s] = 0; else break; std::cout << "RProc4 read : " << buff << std::endl; } close(fd); RemovePipe(NAME_PIPE_4); return 0; }
动图结果演示