Linux进程间通信【匿名管道和命名管道】
进程间通信,就是为了让两个不同进程间协作完成任务,通信的前提就是要构建两个进程之间的联系,构建联系的方法有很多种,本文先来谈谈管道通信
1. 进程间通信介绍
先来介绍一下进程间通信的相关概念
1.1 进程间通信目的
进程间通信的四个目的
- 数据传输:一个进程需要把自己的数据传输给另外一个进程
- 资源共享:多个进程之间共享同样的资源
- 通知事件:一个进程需要向另外一个或多个进程发送消息,通知它们发生某种事件
- 进程控制:有些进程需要完全控制另外一个进程的执行
1.2 进程间通信要求
进程间是有独立性的,不能违背这一原则,所以不能让一个进程直接访问另一个进程的数据
- 要让两个不同的进程进行通信,前提条件就是:==先让两个进程看到同一份“资源”==,这也是进程间通信的本质,这里的“资源”就由操作系统直接或间接的提供
那么后续使用的任何进程间通信手段,无非就是要解决两个问题
- 想办法,先让不同的进程看到同一份“资源”
- 让一方写入,另一方读取,完成通信过程。至于通信目的与后续工作,要结合具体场景
1.3 进程间通信分类
管道:很古老的通信方式
- 匿名管道
- 命名管道
System V 标准:本地化进程通信方式
- 消息队列
- 共享内存
- 信号量
POSIX
标准:网络中进程通信方式
- 消息队列
- 共享内存
- 信号量
- 互斥量(互斥锁)
- 条件变量
- 读写锁
2. 匿名管道
管道是Unix
中最古老的进程间通信的形式,我们把从一个进程连接到另一个进程的一个数据流称为一个“管道”
在命令行中输入|`即可使用管道,我们利用管道来统计一下当前用户登录个数
who
是一个命令,本质它是一个进程,是bash
的子进程,wc
同样是一个bash
的子进程,通过管道的方式把who
进程的数据也让wc
进程看到
Linux
下一切皆文件,管道也是文件,who
进程一般都是从标准输出中获取的信息,wc
进程一般都是从标准输入中获取信息的,将who
进程的标准输出重定向到管道这个文件中,wc
进程则将标准输入重定向到管道文件中,所以这样就可以实现两个进程看到同一份“资源”了
2.1 工作原理
借助上面的例子来讲解一下工作原理
- 创建子进程,只会复制进程相关的数据结构对象,并不会拷贝父进程的文件对象。所以上述两个进程中文件描述符表中每个指针的指向的都是同一个文件对象
- 这就是
fork
之后,父子进程会向同一个显示器打印数据的原因。这里OS
提供的内存文件就是管道文件,这样就可以达成共享同一"资源"。管道文件不是放在磁盘中的,是一个内存文件,它只是支持单向通信(半双工) - 管道文件是确定数据流向的,关闭不需要的
fd
,也就是当who
进程进行write
,wc
进程进行read
的时候,此时who
进程就会关闭read
对应的描述符(读端
),wc
进程就会关闭write
对应的描述符(写端
),这样就可以实现管道之间的单向关系了。这里的这个管道也就是匿名管道,不知道它对应的路径,也不知道对应的文件等等
2.2 pipe函数
#include <unistd.h>
int pipe(int pipefd[2]);
函数详解
- pipe()创建一个管道,这是一个单向数据通道,可用于进程间通信。数组
pipefd
用于返回2引用管道两端的文件描述符。pipefd[0]
表示管道的读端
,pipefd[1]
表示管道的写端
。写入管道写端的数据被内核缓冲,直到从管道的读端读取 - 如果匿名管道创建成功,返回
0
,失败则返回-1
,并适当地设置errno
参数记忆
pipefd[0]
:0
就像嘴巴 ,嘴巴是用来读书的,所以对应读端
pipefd[1]
:1
就像钢笔,钢笔是用来写字 ,所以对应写端
下面来个代码案例
#include <iostream>
#include <unistd.h>
#include <cerrno>
#include <cstring>
#include <cassert>
#include <cstdlib>
#include <string>
#include <stdio.h>
#include <sys/types.h>
using namespace std;
int main()
{
//1. 创建匿名管道
int pipefd[2] = {
0};
int ret = pipe(pipefd);
if(ret == -1)
{
cout << "pipe failed, errno: " << errno << strerror(errno) << endl;
}
cout << "pipefd[0]:" << pipefd[0] << endl; //fd:3 -> 读端
cout << "pipefd[1]:" << pipefd[1] << endl; //fd:4 -> 写端
//2. 创建子进程
pid_t id = fork();
assert(id != -1);
if(id == 0) //子进程(写入)
{
close(pipefd[0]); //关闭读端
//4. 开始通信
int cnt = 5;
char buffer_child[1024]; //缓冲区
while(cnt--)
{
snprintf(buffer_child, sizeof(buffer_child), "我是子进程, 我的PID是: %d, cnt: %d", getpid(), cnt + 1);
write(pipefd[1], buffer_child, strlen(buffer_child));
sleep(1);
}
exit(0);
}
//父进程(读取):
//3. 关闭不需要的fd(父进程读取,子进程写入)
close(pipefd[1]); //关闭写端
char buffer_parent[1024];
int num = 5;
while(num--)
{
int n = read(pipefd[0], buffer_parent, sizeof(buffer_parent) - 1);
if(n == -1)
{
cout << "read failed, errno: " << errno << strerror(errno) << endl;
}
buffer_parent[n] = '\0';
cout << "我是父进程, 子进程给我传递的信息是:" << buffer_parent << endl;
}
return 0;
}
站在文件描述符的角度深入理解管道
站在内核的角度理解管道的本质
所以,看待管道,就如同看待文件一样!管道的使用和文件一致,迎合了“Linux一切皆文件思想”
3. 管道读写规则
管道读写规则
- 当没有数据可读时
read
调用阻塞,即进程暂停执行,一直等到有数据来到为止。read
调用返回-1
,errno
值为EAGAIN
- 当管道满的时候
write
调用阻塞,直到有进程读走数据- 调用返回
-1
,errno
值为EAGAIN
- 如果所有管道写端对应的文件描述符被关闭,则
read
返回0
- 如果所有管道读端对应的文件描述符被关闭,则write操作会产生信号
SIGPIPE
,进而可能导致write
进程退出 PIPE_BUF
为管道大小,Linux
中为4096
字节- 当要写入的数据量不大于
PIPE_BUF
时,Linux
将保证写入的原子性 - 当要写入的数据量大于
PIPE_BUF
时,Linux
将不再保证写入的原子性
- 当要写入的数据量不大于
4. 管道特点
管道的五个特点
- 管道是单向通信(半双工)
- 管道本质是文件,文件描述符声明周期是随进程的,管道的声明周期是随进程的
- 不仅父子进程可以通信,爷孙进程也可以通信,兄弟进程也可以通信,所以管道通信通常用来具有"血缘关系"的进程进行进程间通信。(
pipe()
打开管道并不清楚管道名字 --> 匿名管道) - 写入的次数和读取的次数不是严格匹配的,可能一次写的东西分很多次读,可能多次写的东西一次读取,读写没有强相关
- 如果一个进程
read
端读取完管道所有数据,对方如果不发,那么只能等待;如果write
端写满管道了,不能够写了;管道具有一定的协同能力,让读端和写端能够按照顺序通信(自带同步机制)
5. 管道的特殊场景
管道有四种特殊场景,即管道为空,管道为满,写端关闭,读端关闭,前两种场景比较简单,为空会造成读端阻塞,未满会造成写端阻塞,来演示一下后两种场景
1、关闭写端,读端没有关闭
#include <iostream>
#include <unistd.h>
#include <cerrno>
#include <cstring>
#include <cassert>
#include <cstdlib>
#include <string>
#include <stdio.h>
#include <sys/types.h>
using namespace std;
int main()
{
//1. 创建匿名管道
int pipefd[2] = {
0};
int ret = pipe(pipefd);
if(ret == -1)
{
cout << "pipe failed, errno: " << errno << strerror(errno) << endl;
}
cout << "pipefd[0]:" << pipefd[0] << endl; //fd:3 -> 读端
cout << "pipefd[1]:" << pipefd[1] << endl; //fd:4 -> 写端
//2. 创建子进程
pid_t id = fork();
assert(id != -1);
if(id == 0) //子进程(写入)
{
close(pipefd[0]); //关闭读端
//4. 开始通信
int cnt = 0;
while(true)
{
char x = 'A';
write(pipefd[1], &x, 1);
cout << "cnt:" << cnt << endl;
sleep(1);
break;
}
close(pipefd[1]);
exit(0);
}
//父进程(读取):
//3. 关闭不需要的fd(父进程读取,子进程写入)
close(pipefd[1]); //关闭写端
char buffer_parent[1024];
while(true)
{
int n = read(pipefd[0], buffer_parent, sizeof(buffer_parent) - 1);
if(n == -1)
{
cout << "read is anomaly" << endl;
}
if(n == 0)
{
cout << "read end of file" << endl;
break;
}
buffer_parent[n] = '\0';
cout << "我是父进程, 子进程给我传递的信息是:" << buffer_parent << endl;
}
close(pipefd[0]);
return 0;
}
关闭写端,读端没有关闭,读端再去读取数据,read就会返回0,也就是读到了文件结尾
- 管道是单流向通信,写端关闭也就不会再有数据写入,因此当读端把剩余数据都读取后,每次都是读取
0
字节数据,表明此时已经读到了结尾,读端也就结束读取了
2、关闭读端,写端没有关闭
#include <iostream>
#include <unistd.h>
#include <cerrno>
#include <cstring>
#include <cassert>
#include <cstdlib>
#include <string>
#include <stdio.h>
#include <sys/types.h>
using namespace std;
int main()
{
//1. 创建管道
int pipefd[2] = {
0};
int fd_result = pipe(pipefd);
if(fd_result == -1)
{
cout << "pipe failed, errno: " << errno << strerror(errno) << endl;
}
cout << "pipefd[0]:" << pipefd[0] << endl; //fd:3 -> 读端
cout << "pipefd[1]:" << pipefd[1] << endl; //fd:4 -> 写端
//2. 创建子进程
pid_t id = fork();
assert(id != -1);
if(id == 0) //子进程(写入)
{
close(pipefd[0]); //关闭读端
//4. 开始通信
int cnt = 0;
while(true)
{
char x = 'A';
write(pipefd[1], &x, 1);
cout << "cnt:" << cnt << endl;
sleep(1);
}
close(pipefd[1]);
exit(0);
}
//父进程(读取):
//3. 关闭不需要的fd(父进程读取,子进程写入)
close(pipefd[1]); //关闭写端
char buffer_parent[1024];
while(true)
{
//sleep(10);
int n = read(pipefd[0], buffer_parent, sizeof(buffer_parent) - 1);
if(n == -1)
{
cout << "read is anomaly" << endl;
break;
}
if(n == 0){
cout << "read end of file" << endl;
break;
}
buffer_parent[n] = '\0';
cout << "我是父进程, 子进程给我传递的信息是:" << buffer_parent << endl;
sleep(1);
break;
}
close(pipefd[0]);
return 0;
}
关闭读端,写端没有关闭,这样就没有意义,OS
不会允许浪费资源的行为,OS
会通过信号直接kill
掉一直在写入的进程,13
号信号就是用来终止管道写端进程的
6. 匿名管道进程池
实现功能:
- 父进程创建一批子进程,通过多条匿名管道与它们链接通信,向子进程下达指定的任务
实现模型
实现源码
Task.hpp
#include <iostream>
#include <assert.h>
#include <unistd.h>
#include <vector>
#include <string>
#include <sys/types.h>
#include <sys/wait.h>
class manage_child;
class Task;
#define CHILD_PROCESS_NUM 3
void create_frame(std::vector<manage_child>& manage);
void control_child_process(const std::vector<manage_child>& manage);
void recycle_process(const std::vector<manage_child>& manage);
class manage_child
{
public:
manage_child(int fd, int id)
:_write_fd(fd)
,_child_id(id)
{
}
~manage_child(){
}
public:
int _write_fd;
pid_t _child_id;
};
typedef void(*fun_p)();
#define GET_NET 1
#define POLL_SERVER 2
#define PUSH_SOURCE 3
void get_net();
void poll_server();
void push_source();
class Task
{
public:
Task()
{
funcs.push_back(get_net);
funcs.push_back(poll_server);
funcs.push_back(push_source);
}
void execute_task(int option){
assert(option >= 1 && option <= 3);
funcs[option - 1]();
}
~Task(){
}
private:
std::vector<fun_p> funcs;
};
ctrlProcess.cc
#include "ctrlProcess.hpp"
void get_net()
{
std::cout << "子进程:PID:" << getpid() << "获取网络资源中........." << std::endl;
}
void poll_server()
{
std::cout << "子进程:PID:" << getpid() << "下载服务资源中........" << std::endl;
}
void push_source()
{
std::cout << "子进程:PID:" << getpid() << "发送服务资源中........" << std::endl;
}
void execute_command(int read_fd)
{
Task task;
while(true){
int command = 0;
int read_return = read(read_fd, &command, sizeof(int));
if(read_return == sizeof(int)){
//执行任务
task.execute_task(command);
}else{
break;
}
}
}
void create_frame(std::vector<manage_child>& manage)
{
std::vector<int> fds;
for(int i = 0; i < CHILD_PROCESS_NUM; ++i){
//创建管道
int pipefd[2];
int pipe_return = pipe(pipefd);
assert(pipe_return == 0);
(void)pipe_return;
//创建子进程
pid_t id = fork();
assert(id != -1);
if(id == 0){
//子进程 - 读
for(auto& fd : fds) close(fd); //关闭子进程拷贝父进程的写端
close(pipefd[1]);
//dup2(pipefd[0], 0);
execute_command(pipefd[0]);
close(pipefd[0]);
exit(0);
}
//父进程
close(pipefd[0]);
//父进程对子进程和写端组织管理
manage.push_back(manage_child(pipefd[1], id));
fds.push_back(pipefd[1]);
}
}
void show_option(){
std::cout << "-----------------------------------------" << std::endl;
std::cout << "--- 1. 获取网络资源 2. 下载服务资源 ---" << std::endl;
std::cout << "--- 3. 发送服务资源 4. 退出服务系统 ---" << std::endl;
std::cout << "-----------------------------------------" << std::endl;
}
void control_child_process(const std::vector<manage_child>& manage)
{
while(true){
//选择任务
show_option();
std::cout << "请选择->";
int command = 0;
std::cin >> command;
if(command == 4) break;
if(command < 1 || command > 3) continue;
//选择进程
int rand_index = rand() % manage.size();
std::cout << "被选中的子进程:" << manage[rand_index]._child_id << std::endl;
//分发任务
write(manage[rand_index]._write_fd, &command, sizeof(command));
sleep(1);
}
}
void recycle_process(const std::vector<manage_child>& manage)
{
for(int i = 0; i < manage.size(); ++i){
std::cout << "父进程让子进程退出" << manage[i]._child_id << std::endl;
close(manage[i]._write_fd);
waitpid(manage[i]._child_id, nullptr, 0); //阻塞式等待
std::cout << "父进程回收子进程:" << manage[i]._child_id << std::endl;
}
sleep(5); //父进程退出
}
int main()
{
//创建框架:一个父进程控制多个子进程(父进程写,子进程读)
std::vector<manage_child> manage;
create_frame(manage);
//父进程控制任意子进程执行任务
control_child_process(manage);
//回收子进程并关闭管道
recycle_process(manage);
return 0;
}
7. 命名管道
命名管道的特点是自带同步与互斥机制、数据单向流通,与匿名管道不同的是,命名管道有自己的名字,因此可以被没有血缘关系的进程看到,所以命名管道可以实现两个独立进程间通信
7.1 概念理解
命名管道(named pipe)又被称为先进先出队列(FIFO),是一种特殊的管道,存在于文件系统中。命名管道与管道非常类似,但是又有自身的显著特征:
- 命名管道可以用于任何两个进程间的通信,而不限于同源的两个进程
- 命名管道作为一种特殊的文件存放在文件系统中,而不是像匿名管道那样存放在内核中。当进程对命名管道的使用结束后,命名管道依然存在于文件系统中,除非对其进行删除操作,否则该命名管道不会自行消失
- 命名管道就是给匿名管道起名字,给匿名管道这个内存文件分配
inode
,将文件名与之构建联系,但是不给它分配Data block
,它是一个内存文件不需要将数据刷盘到磁盘中
7.2 创建和使用
使用系统调用接口mkfifo()
,来创建命名管道
#include <sys/types.h>
#include <sys/stat.h>
int mkfifo(const char *pathname, mode_t mode);
mkfifo()
函数
pathname
参数:创建命名管道文件时的路径和名字,既可以传递绝对路径也可以传递相对路径mode
参数:创建命令管道文件时的权限,mode_t
类型就是对unsigned int
的封装,等价于uint32_t
- 返回值:创建成功返回
0
,失败则返回-1
mkfifo
还可以直接在命令行创建命名管道文件
mkfifo 命名管道文件名 //创建命名管道文件
可见管道文件的类型为p
,大小为0
,这也就说明管道文件就是一个内存级文件,有自己的上限,在文件系统中只是挂了个名
使用系统调用接口unlink()
,来删除命名管道
#include <unistd.h>
int unlink(const char *pathname);
返回值和参数作用和mkfifo()
相同,用于删除指定命名管道
当然也可以在命令行使用
unlink 命令管道文件名 //删除命名管道文件
7.3 不同进程间通信
我们可以利用命名管道来模拟两个进程间的通信
- 服务端
server
创建管道文件,以读的方式打开,客户端client
以写的方式打开管道文件,打开后让两个进程通信,通信结束后,客户端关闭写端,服务端读取到0
后关闭并删除命名管道文件
common.hpp
公共资源
#include <iostream>
#include <sys/types.h>
#include <sys/stat.h>
#include <string>
#include <assert.h>
#include <fcntl.h>
#include <unistd.h>
#include <cstring>
#include <strings.h>
const std::string path_name = "./fifo"; //管道名
#define MODE 0664 //权限
client.cc
#include "common.hpp"
int main()
{
//客户端
//打开文件
int open_fd = open(path_name.c_str(), O_WRONLY);
assert(open_fd != -1);
//写入数据,进行通信
while(true){
char buffer[1024];
if(strcasecmp(buffer, "quit") == 0){
break;
}
std::cout << "请输入:>";
char* message = fgets(buffer, sizeof(buffer), stdin);
buffer[strlen(buffer) - 1] = '\0';
assert(message != nullptr);
(void)message;
write(open_fd, buffer, strlen(buffer));
}
close(open_fd);
return 0;
}
sercer.cc
#include "common.hpp"
int main()
{
//服务端
//创建命名管道
umask(0);
int mkfifo_ret = mkfifo(path_name.c_str(), MODE);
assert(mkfifo_ret != -1);
//打开文件并读取
int open_fd = open(path_name.c_str(), O_RDONLY);
assert(open_fd != -1);
while(true){
char buffer[1024];
ssize_t size = read(open_fd, buffer, sizeof(buffer) - 1);
if(size > 0){
buffer[size] = '\0';
std::cout << buffer << std::endl;
}else{
break;
}
}
close(open_fd);
//关闭命名管道
int unlink_ret = unlink(path_name.c_str());
assert(unlink_ret != -1);
return 0;
}
7.4 两种管道的区别
命名管道与匿名管道的区别
- 匿名管道只能用于具有血缘关系的进程间通信,命名管道谁都可以用
- 匿名管道直接通过
pipe
函数创建使用,命名管道需要先通过mkfifo
函数创建,然后再通过open
打开使用 - 出现多条匿名管道时,可能会出现写端
fd
重复继承的情况,命名管道不会出现这种情况
8. 命名管道进程池
ControlCenter.cc
#include "NamepipePool.hpp"
void create_namepipe()
{
int fifo_net_request_ret = mkfifo(fifo_net_request.c_str(), MODE);
assert(fifo_net_request_ret != -1);
int fifo_dispose_data_ret = mkfifo(fifo_dispose_data.c_str(), MODE);
assert(fifo_dispose_data_ret != -1);
int fifo_manage_system_ret = mkfifo(fifo_manage_system.c_str(), MODE);
assert(fifo_manage_system_ret != -1);
}
Manage_fifo manage_namepipe()
{
std::cout << "打开fifo_net_request......" << std::endl;
sleep(1);
int fifo_net_request_fd = open(fifo_net_request.c_str(), O_RDWR);
assert(fifo_net_request_fd != -1);
std::cout << "打开fifo_dispose_data......." << std::endl;
sleep(1);
int fifo_dispose_data_fd = open(fifo_dispose_data.c_str(), O_RDWR);
assert(fifo_dispose_data_fd != -1);
std::cout << "打开fifo_manage_system........" << std::endl;
sleep(1);
int fifo_manage_system_fd = open(fifo_manage_system.c_str(), O_RDWR);
assert(fifo_manage_system_fd != -1);
Manage_fifo center( fifo(fifo_net_request_fd, fifo_net_request)
, fifo(fifo_dispose_data_fd,fifo_dispose_data)
, fifo(fifo_manage_system_fd,fifo_manage_system));
std::cout << "命名管道全部打开!" << std::endl;
return center;
}
void task_menu()
{
std::cout << "----------------------------------------------" << std::endl;
std::cout << "-- 1.网络请求 2.数据处理 --" << std::endl;
std::cout << "-- 3.系统管理 4.退出中控 --" << std::endl;
std::cout << "----------------------------------------------" << std::endl;
}
void write_fifo(int& command, Manage_fifo& center)
{
int buf = command;
for(int i = 0; i < PROCESS_NUM; ++i){
if(command - 1 == i){
write(center._fifos[i]._fifo_fd, &buf, sizeof(buf));
break;
}
}
}
void close_fifo(Manage_fifo& center)
{
for(int i = 0; i < PROCESS_NUM; ++i){
close(center._fifos[i]._fifo_fd);
unlink(center._fifos[i]._fifo_name.c_str());
}
}
//主控进程管理命令管道写入->任务进程读取执行
int main()
{
//1. 创建管道文件
create_namepipe();
//2. 打开文件做管理
Manage_fifo center;
try
{
center = manage_namepipe(); //TODO(拷贝构造)
}
catch(const std::exception& e)
{
std::cerr << e.what() << '\n';
}
std::cout << "开始执行任务" << std::endl;
//3. 通过选择执行任务
while(true)
{
//1. 选择执行任务
// > 列出菜单
task_menu();
// > 输入
int command = 0;
std::cout << "请求输入#";
std::cin >> command;
if(command == 4){
break;
}
if(command < 1 || command > 4){
std::cout << "输入错误,请重新输入!";
continue;
}
//2. 执行选择写入对应进程
write_fifo(command, center);
sleep(1);
}
//3. 关闭所有命名管道
close_fifo(center);
(void)center;
return 0;
}
DisposeData.cc
#include "NamepipePool.hpp"
int main()
{
int fd = open(fifo_dispose_data.c_str(), O_RDWR);
assert(fd != -1);
int buf = 0;
ssize_t size = read(fd, &buf, sizeof(buf));
assert(size >= 0);
if(buf == FIFO_DISPOSE_DATA){
int cnt = 5;
while(cnt > 0)
{
printf("数据库正在处理数据中..............(请等待<%d>秒钟)\n", cnt--);
sleep(1);
}
}
if(size == -1){
std::cout << "dispose_data进程读取错误";
exit(0);
}
return 0;
}
ManageSystem.cc
#include "NamepipePool.hpp"
int main()
{
int fd = open(fifo_manage_system.c_str(), O_RDWR);
assert(fd != -1);
int buf = 0;
while(true)
{
ssize_t size = read(fd, &buf, sizeof(buf));
assert(size >= 0);
if(buf == FIFO_MANAGE_SYSTEM){
int cnt = 5;
while(cnt > 0)
{
printf("系统正在管理各个子系统中..............(请等待<%d>秒钟)\n", cnt--);
sleep(1);
}
break;
}
if(size == -1){
std::cout << "manage_system进程读取错误";
exit(0);
}
}
return 0;
}
NamepipePool.hpp
#include <iostream>
#include <sys/types.h>
#include <sys/stat.h>
#include <string>
#include <vector>
#include <unistd.h>
#include <fcntl.h>
#include <cstring>
#include <assert.h>
//管道名
std::string fifo_net_request = "./fifo_net_request";
std::string fifo_dispose_data = "./fifo_dispose_data";
std::string fifo_manage_system = "./fifo_manage_system";
#define MODE 0664
#define FIFO_NET_REQUEST 1
#define FIFO_DISPOSE_DATA 2
#define FIFO_MANAGE_SYSTEM 3
#define PROCESS_NUM 3
class fifo
{
public:
fifo(const int& fd, std::string& name)
:_fifo_fd(fd)
,_fifo_name(name)
{
}
fifo(const fifo& x)
{
_fifo_fd = x._fifo_fd;
_fifo_name = x._fifo_name;
}
~fifo(){
}
public:
int _fifo_fd;
std::string _fifo_name;
};
class Manage_fifo
{
public:
Manage_fifo(){
}
Manage_fifo(const fifo fd1, const fifo fd2, const fifo fd3)
{
_fifos.push_back(fd1);
_fifos.push_back(fd2);
_fifos.push_back(fd3);
}
~Manage_fifo(){
}
public:
std::vector<fifo> _fifos;
};
NetRequest.cc
#include "NamepipePool.hpp"
int main()
{
int fd = open(fifo_net_request.c_str(), O_RDWR);
assert(fd != -1);
int buf = 0;
ssize_t size = read(fd, &buf, sizeof(buf));
assert(size > 0);
if(buf == FIFO_NET_REQUEST){
int cnt = 5;
while(cnt > 0)
{
printf("网络正在请求中..............(请等待<%d>秒钟)\n", cnt--);
sleep(1);
}
}
if(size == -1){
std::cout << "net_request进程读取错误";
exit(0);
}
return 0;
}
Makefile
.PHONY:all
all:ControlCenter ManageSystem NetRequest DisposeData
ControlCenter:ControlCenter.cc
g++ -o {
mathJaxContainer[0]}^ -std=c++11 -g
ManageSystem:ManageSystem.cc
g++ -o {
mathJaxContainer[1]}^ -std=c++11
NetRequest:NetRequest.cc
g++ -o {
mathJaxContainer[2]}^ -std=c++11 -g
DisposeData:DisposeData.cc
g++ -o {
mathJaxContainer[3]}^ -std=c++11
.PHONY:clean
clean:
rm -f ControlCenter ManageSystem NetRequest DisposeData
rm -f fifo_*
Linux进程间通信【匿名管道和命名管道】,到这里就介绍结束了,本篇文章对你由帮助的话,期待大佬们的三连,你们的支持是我最大的动力!
文章有写的不足或是错误的地方,欢迎评论或私信指出,我会在第一时间改正