已解决
命名管道原理(和匿名管道的对比),mkfifo(命令行,函数),命名管道模拟实现代码+与多个子进程通信代码
来自网友在路上 190890提问 提问时间:2023-11-08 23:47:37阅读次数: 90
最佳答案 问答题库908位专家为你答疑解惑
目录
命名管道
引入
原理
和匿名管道的对比
使用 -- mkfifo
命令行指令
创建
文件类型p
使用
函数
函数原型
模拟实现
头文件
客户端代码
服务端代码
运行情况
模拟实现 -- 与多个子进程
介绍
服务端代码:
运行情况
命名管道
引入
匿名管道只能用于父子进程之间通信,如果我们想要两个完全无关联的进程通信该怎么办?
- 首先,通信本质还是不变的 : 要让不同的进程看到同一份资源
- 依然还是用文件作为中间介质,但拿到文件的方式不同
原理
- 如果一个进程打开一个文件,另一个进程也想打开这个文件:
- 直接让该进程也指向这个已存在的file结构体(不需要再创建一个file,否则内存中会存在大量相同的数据)
- 但是!普通文件的数据是要被刷新到磁盘上的
- 我们的目的可不是为了将数据写到磁盘,而是让两个进程进行通信
- 因此需要尽量避免io(1是 io速度太慢,2是 通信过程产生的数据没必要写到磁盘上)
- 因此,管道文件油然而生(也就是命名管道),它是一种特殊的文件
- 它一旦被打开,就会有自己的路径(路径具有唯一性)
- 因此,不同进程就可以通过唯一的路径来访问同一个管道文件
和匿名管道的对比
两种管道本质上都是一样的(都是文件)
但实现[让不同进程看到同一份资源]的手段不同
- 匿名管道 -- 子进程继承父进程的文件描述符表,[直接用fd拿到文件]
- 命名管道 -- 两个进程访问同一路径下的文件,[用路径拿到文件]
使用 -- mkfifo
命令行指令
创建
文件类型p
p(pipe) -- 管道文件
使用
当只有一个进程打开该管道时,会阻塞
当两个不同进程打开同一路径的管道文件(一个命令就是一个进程 ,echo和cat)
就可以进行通信噜
函数
函数原型
模拟实现
头文件
comm.hpp:
#ifndef COMM_H #define COMM_H#include <iostream> #include <cstring> #include <sys/types.h> #include <sys/stat.h> #include <string> #include <fcntl.h> #include<unistd.h>using namespace std;string pipe_path = "./fifo.ipc"; #define mode 0666 #define num 1024#endif
log.hpp:
#pragma once#include <iostream> #include <string> #include<time.h>using namespace std;#define debug 0 #define notice 1 #define warning 2 #define error 3const string msg[] //定义不同类型的信息状态 {"debug", "notice", "warning", "error" };ostream& log(string message,int level) { cout<<"|"<<(unsigned)time(nullptr)<<"|"<<message<<"|"<<msg[level]<<"|"<<endl;return cout; }
客户端代码
#include"comm.hpp"//用于发送信息(客户端) int main(){//文件操作int fd=open(pipe_path.c_str(),O_WRONLY|O_TRUNC);if(fd<0){perror("open");exit(1);}string buffer;while(true){cout<<"Please enter the information you want to send : "<<endl;getline(cin,buffer); //输入要发送的信息int size=write(fd,buffer.c_str(),buffer.size());//向管道文件写入if(size<0){perror("write");exit(2);}else if(size==0){break;}} exit(fd);return 0; }
服务端代码
#include "comm.hpp" #include"log.hpp"// 用于接收信息(服务端)int main() {// 创建管道文件if (mkfifo(pipe_path.c_str(), mode) < 0){perror("mkfifo");}log("创建管道文件成功",debug);// 文件操作int fd = open(pipe_path.c_str(), O_RDONLY);if (fd < 0){perror("open");exit(1);}log("打开文件成功",debug);// 进行通信char buffer[num];while (true){memset(buffer, 0, sizeof buffer);ssize_t size = read(fd, buffer, sizeof buffer - 1);//读取管道文件中的内容cout<<size<<endl;if (size < 0){perror("read");exit(2);}else if (size == 0){cerr << "read end , client quit , sever quit too " << endl;break;}else{cout << "send_message is : " << buffer << endl;log("读取信息成功",debug);}}// 关闭close(fd);log("关闭管道文件成功",debug);unlink(pipe_path.c_str());log("删除管道文件成功",debug);return 0; }
运行情况
创建管道,等待另一方打开该管道
一端打开文件后,另一端才打开
服务端收到客户端发送的信息
客户端关闭,服务端也退出
当服务端关闭,客户端也会退出
模拟实现 -- 与多个子进程
介绍
- 其他部分与上面相同,只需要在服务端修改
- 将读取信息的部分分装一个函数
- 然后在服务端创建子进程,让子进程去读取客户端发送的信息
服务端代码:
#include "comm.hpp" #include"log.hpp"// 用于接收信息(服务端)void recive_message(int fd){char buffer[num];while (true){memset(buffer, 0, sizeof buffer);ssize_t size = read(fd, buffer, sizeof buffer - 1);//cout<<size<<endl;if (size < 0){perror("read");exit(2);}else if (size == 0){cerr <<"[ " << getpid() << " ]" << "read end , client quit , sever quit too " << endl;break;}else{cout << "[ " << getpid() << " ]" <<" send_message is : " << buffer << endl;log("读取信息成功",debug);}} } int main() {// 创建管道文件if (mkfifo(pipe_path.c_str(), mode) < 0){perror("mkfifo");}log("创建管道文件成功",debug);// 文件操作int fd = open(pipe_path.c_str(), O_RDONLY);if (fd < 0){perror("open");exit(1);}log("打开文件成功",debug);for(int i=0;i<process_size;i++){size_t id=fork();if(id==0){recive_message(fd); //创建子进程去读取exit(0);}}for(int i=0;i<process_size;i++){pid_t ret=waitpid(-1,nullptr,0);}// 关闭close(fd);log("关闭管道文件成功",debug);unlink(pipe_path.c_str());log("删除管道文件成功",debug);return 0; }
运行情况
查看全文
99%的人还看了
相似问题
猜你感兴趣
版权申明
本文"命名管道原理(和匿名管道的对比),mkfifo(命令行,函数),命名管道模拟实现代码+与多个子进程通信代码":http://eshow365.cn/6-35678-0.html 内容来自互联网,请自行判断内容的正确性。如有侵权请联系我们,立即删除!