6.【Linux】进程间通信(管道命名管道||简易进程池||简易客户端服务端通信)

介绍

进程间通信的方式

1.Linux原生支持的管道----匿名和命名管道
2.System V-----共享内存、消息队列、信号量
3.Posix------多线程、网路通信

进程间通信目的

数据传输:一个进程需要将它的数据发送给另一个进程
资源共享:多个进程之间共享同样的资源。
通知事件:一个进程需要向另一个或一组进程发送消息,通知它(它们)发生了某种事件(如进程终止时要通知父进程)。
进程控制:有些进程希望完全控制另一个进程的执行(如Debug进程),此时控制进程希望能够拦截另一个进程的所有陷入和异常,并能够及时知道它的状态改变

管道

原理

管道是单向通信的,常用于有亲缘关系的父子间通信,父进程调用pipe打开管道文件,操作系统创建struct file结构体(存有inode等文件信息),父进程fd指向该文件,父进程fork出子进程,子进程也拷贝父进程的代码和fd,同时fd指向管道,分别关闭读端和写端,从而实现单向通信。
在这里插入图片描述

创建管道

在这里插入图片描述
调用成功返回0,失败返回-1。pipefd是输出型参数,pipefd【0】为3,pipefd【1】为4.

构建单向通信的读端(子进程关闭写端)

//2.create child processpid_t id=fork();assert(id!=-1);if(id==0){//child process//3构建单向通行的信道pipe[0]:read,pipe[1]:write//3.1关闭子进程不需要的fdclose(pipefd[1]);char buffer[1025];while(true){ssize_t s=read(pipefd[0],buffer,sizeof(buffer)-1);if(s>0){buffer[s]=0;cout<<"child get a message["<<getpid()<<"]father"<<buffer<<endl;}}exit(0);}

写端(父进程关闭读端)

	close(pipefd[0]);string message="我是父进程,我正在给你发消息";int count=0;char send_buffer[1024];while(true){//3.2构建一个变化的字符串snprintf(send_buffer,sizeof(send_buffer),"%s:%d",message.c_str(),count++);//3.3写入write(pipefd[1],send_buffer,strlen(send_buffer));//3.4故意睡一会sleep(1);}pid_t ret=waitpid(id,nullptr,0);assert(ret<0);(void)ret;close(pipefd[1]);

管道特点

1.常用于亲缘关系的父子间通信
2.提供访问控制(例如管道无数据时读端就必须等数据写入)
3.管道本质是内核中的一块缓冲区,多个进程通过访问同一块缓冲区实现通信。
4. 管道提供的是面向流式的通信服务(面向字节流),需要定制协议来进行数据区分。
5.管道是基于文件的,文件的生命周期是随进程的,那么管道的生命周期也是随进程的。
6.管道是单向通信的,就是半双工通信的一种特殊情况,数据只能向一个方向流动。需要双方通信时,需要建立起两个管道。半双工通信就是要么在收数据,要么在发数据,不能同时在收数据和发数据(比如两个人在交流时,一个人在说,另一个人在听);而全双工通信是同时进行收数据和发数据(比如两个人吵架的时候,相互问候对方,一个人既在问候对方又在听对方的问候)。

实现一个简易进程池

process.cc

#include<iostream>
#include<unistd.h>
#include<stdlib.h>
#include<sys/wait.h>
#include<sys/types.h>
#include<assert.h>
#include<vector>
#include<cstdlib>
#include<time.h>
#include"Task.hpp"#define PROCESS_NUM 5using namespace std;int waitCommand(int waitFd,bool &quit)
{uint32_t command=0;ssize_t s=read(waitFd,&command,sizeof(command));if(s==0){quit=true;return -1;}assert(s==sizeof(uint32_t));return command;
}//给哪一个进程通过什么文件描述符发送什么命令
void  sendAndWakeUp(pid_t who,int fd,uint32_t command)
{write(fd,&command,sizeof(command));cout<<"call process"<<who<<"execute"<<desc[command]<<"through"<<fd<<endl;
}int main()
{Load();vector<pair<pid_t,int>> slots;//先创建多个进程for(int i=0;i<PROCESS_NUM;i++){int pipefd[2]={0};int n=pipe(pipefd);assert(n==0);(void)n;pid_t id=fork();assert(id!=-1);if(id==0){//child读取,关闭写端close(pipefd[1]);while(true){bool quit=false;//pipefd[0]int command=waitCommand(pipefd[0],quit);//如果不发,则阻塞if(quit)    break;if(command>=0&&command<handlerSize()){callbacks[command]();}else{cout<<"非法command"<<endl;}}exit(1);}close(pipefd[0]);slots.push_back(pair<pid_t,int>(id,pipefd[1]));}//开始任务srand((unsigned long)time(nullptr));while(true){int select,command;cout<<"##############"<<endl;cout<<"1.show functions"<<endl;cout<<"2.send command"<<endl;cout<<"Please select";cin>>select;if(1==select){showHandler();}else if(select==2){cout<<"Enter Your Command:";cin>>command;//选择进程int choice_procID=rand()%slots.size();//布置任务给指定进程sendAndWakeUp(slots[choice_procID].first,slots[choice_procID].second,command);}}//关闭fd,所有的子进程都会退出for(const auto& slot:slots){close(slot.second);}//回收所有的子进程信息for(const auto& slot: slots){waitpid(slot.first,nullptr,0);}return 0;
}

task.hpp

#pragma once#include<iostream>
#include<string>
#include<unistd.h>
#include<functional>
#include<vector>
#include<unordered_map>typedef std::function<void()> func;std::vector<func> callbacks;
std::unordered_map<int,std::string> desc;void readMySQL()
{std::cout<<"process["<<getpid()<<"]执行访问数据库的任务"<<std::endl;
}void  execuleURL()
{std::cout<<"process["<<getpid()<<"]执行url解析"<<std::endl;
}void  cal()
{std::cout<<"process["<<getpid()<<"]执行加密任务"<<std::endl;
}void save()
{std::cout<<"process"<<getpid()<<"执行数据持久化任务"<<std::endl;
}void Load()
{desc.insert({callbacks.size(),"readMySQL"});callbacks.push_back(readMySQL);desc.insert({callbacks.size(),"execul"});callbacks.push_back(execuleURL);desc.insert({callbacks.size(),"cal"});callbacks.push_back(cal);desc.insert({callbacks.size(),"save"});callbacks.push_back(save);}void showHandler()
{for(const auto& iter:desc){std::cout<<iter.first<<"\t"<<iter.second<<std::endl;}
}int handlerSize()
{return callbacks.size();
}

命名管道

引入

管道应用的一个限制就是只能在具有共同祖先(具有亲缘关系)的进程间通信。
如果我们想在不相关的进程之间交换数据,可以使用FIFO文件来做这项工作,它经常被称为命名管道。命名管道是一种特殊类型的文件。

区别(打开方式,是否存在于文件系统,血缘)

匿名管道不属于文件系统,是一种特殊的文件,只存在于内存中,只能进行血缘关系间的通信。命名管道可用于无关联的进程间通信,mkfifo函数调用后需用open打开,因为它以FIFO文件的形式存在于文件系统中。

实现一个简易的客户端和服务端

//comm.hpp
#ifndef _COMM_H
#define _COMM_H#include<iostream>
#include<string>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<unistd.h>
#include<cstdio>
#include<cstring>
#include"log.hpp"using namespace std;string ipcPath="./fifo.ipc";
const int MODE=0666;
const int SIZE=128;#endif//server.cc
#include"comm.hpp"int main()
{//1.创建命名管道if(mkfifo(ipcPath.c_str(),MODE)<0){perror("mkfifo");exit(1);}Log("创建管道文件成功",Debug)<<"step1"<<endl;//2.打开命名管道int fd=open(ipcPath.c_str(),O_RDONLY);if(fd<0){perror("open");exit(2);}Log("打开成功",Debug)<<"step2"<<endl;//3.读取数据char buf[SIZE];while(true){memset(buf,'\0',sizeof(buf));ssize_t s=read(fd,buf,sizeof(buf)-1);//'\0'不读if(s>0){cout<<"client say:"<<buf<<endl;}else if(s==0){//EOFcerr<<"client quit!"<<endl;break;}else{//errorperror("read");break;}}//4.关闭文件close(fd);unlink(ipcPath.c_str());Log("关闭成功",Debug)<<"step 3"<<endl;return 0;
}//client.cc
#include"comm.hpp"
int main()
{//获取管道文件int fd=open(ipcPath.c_str(),O_WRONLY);if(fd<0){perror("open");exit(1);}//ipc通信过程string buffer;while(true){cout<<"please input:"<<endl;getline(cin,buffer);write(fd,buffer.c_str(),buffer.size());}close(fd);return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://xiahunao.cn/news/2868483.html

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

UE4_调试工具_绘制调试球体

学习笔记&#xff0c;仅供参考&#xff01; 效果&#xff1a; 步骤&#xff1a; 睁开眼睛就是该变量在此蓝图的实例上可公开编辑。 勾选效果&#xff1a;

VUE3生命周期钩子

概念 每个 Vue 组件实例在创建时都需要经历一系列的初始化步骤&#xff0c;比如设置好数据侦听&#xff0c;编译模板&#xff0c;挂载实例到 DOM&#xff0c;以及在数据改变时更新 DOM。在此过程中&#xff0c;它也会运行被称为生命周期钩子的函数&#xff0c;让开发者有机会在…

文件包含例子

一、常见的文件包含函数 php中常见的文件包含函数有以下四种&#xff1a; include() require() include_once() require()_once() include与require基本是相同的&#xff0c;除了错误处理方面: include()&#xff0c;只生成警告&#xff08;E_WARNING&#xff09;&#x…

基于java+springboot+vue实现的自习室管理和预约系统(文末源码+Lw)23-177

摘 要 传统办法管理信息首先需要花费的时间比较多&#xff0c;其次数据出错率比较高&#xff0c;而且对错误的数据进行更改也比较困难&#xff0c;最后&#xff0c;检索数据费事费力。因此&#xff0c;在计算机上安装自习室管理和预约系统软件来发挥其高效地信息处理的作用&a…

Python爬取淘宝商品评价信息实战

文章目录 一、分析需要爬取的页面二、实现爬取商品评价信息的代码1、通过解析显示评价信息的元素获取商品评价信息2、通过mitmproxy代理进行流量抓包获取商品评价信息 三、附-完整代码 前期出了一个《爬取京东商品评价信息实战》的教程&#xff0c;最近又有网友提到要出一个爬淘…

案例分析篇13:系统分析与设计考点(2024年软考高级系统架构设计师冲刺知识点总结系列文章)

专栏系列文章推荐: 2024高级系统架构设计师备考资料(高频考点&真题&经验)https://blog.csdn.net/seeker1994/category_12593400.html 【历年案例分析真题考点汇总】与【专栏文章案例分析高频考点目录】(2024年软考高级系统架构设计师冲刺知识点总结-案例分析篇-…

幸福金龄会第二届《锦绣中华》广东省中老年协会携团队共襄盛举

近日&#xff0c;一场盛大的文化艺术盛宴——第二届《锦绣中华》中老年文旅文化艺术节在广东隆重举行。此次活动由幸福金龄会主办&#xff0c;吸引了广东省内各中老年协会的领导及文艺团队纷纷参与&#xff0c;共同为中华文化的传承与发展贡献力量。 广东省各中老年协会的会长、…

Java项目:56 ssm681基于Java的超市管理系统+jsp

作者主页&#xff1a;源码空间codegym 简介&#xff1a;Java领域优质创作者、Java项目、学习资料、技术互助 文中获取源码 项目介绍 功能包括:商品分类&#xff0c;供货商管理&#xff0c;库存管理&#xff0c;销售统计&#xff0c;用户及角色管理&#xff0c;等等功能。项目采…

WpsOfficeExcel表格固定首行,点视图下的冻结窗格下的冻结首行

wps 和 微软 excel 表格固定首行的方法基本一样 WpsExcel表格固定首行,点视图下的冻结窗格下的冻结首行 WpsExcel表格固定首行,点视图下的冻结窗格下的冻结首行 Excel表格固定首行,点视图下的冻结窗格下的冻结首行 在Excel中固定首行&#xff0c;通常是通过“冻结窗格”功能…

复现文件上传漏洞

一、搭建upload-labs环境 将下载好的upload-labs的压缩包&#xff0c;将此压缩包解压到WWW中&#xff0c;并将名称修改为upload&#xff0c;同时也要在upload文件中建立一个upload的文件。 然后在浏览器网址栏输入&#xff1a;127.0.0.1/upload进入靶场。 第一关 选择上传文件…

综合实验---Web---进阶版

实验配置&#xff1a; 7-1为内网Nginx服务器&#xff1b;7-2和7-3为Web服务器&#xff1b;7-4为网关服务器&#xff1b;7-5为外网客户机&#xff1b; yum安装Nginx&#xff1b;yum安装Mysql&#xff1b; 编译安装PHP&#xff1b;编译安装 由于我们Nginx和Mysql都是yum安装&…

webserver烂大街?还有必要做么?

目录 什么是 Web Server&#xff1f; 如何提供 HTTP 服务&#xff1f; HTTP协议 简介 工作原理 工作步骤 HTTP请求报文格式 HTTP响应报文格式 HTTP请求方法 HTTP状态码 ​总结 都说webserver是C选手人手必备的烂大街项目&#xff0c;那么webserver 还有必要做么&…

CAP 理论:分布式场景下我们真的只能三选二吗?

什么是 CAP 理论 CAP 理论是加州理工大学伯克利分校的 Eric Brewer 教授在 2000 年 7 月的 ACM PODC 会议上首次提出的&#xff0c;它是 Eric Brewer 在 Inktomi 期间研发搜索引擎、分布式 Web 缓存时得出的关于数据一致性&#xff08; C&#xff1a;Consistency &#xff09;…

【C++庖丁解牛】List容器的介绍及使用 | 深度剖析 | list与vector的对比

&#x1f341;你好&#xff0c;我是 RO-BERRY &#x1f4d7; 致力于C、C、数据结构、TCP/IP、数据库等等一系列知识 &#x1f384;感谢你的陪伴与支持 &#xff0c;故事既有了开头&#xff0c;就要画上一个完美的句号&#xff0c;让我们一起加油 目录 1. list的介绍1.1 list的…

selenium + robotframework的运行原理

1、点击ride界面启动用例执行时&#xff0c;首先会调用脚本 2、打开pybot脚本查看内容、 3、打开robot包下面的run文件&#xff0c;我们可以看到信息 run文件内容 程序启动的入口&#xff0c; sys.agv所表达的含义是&#xff1a;sys.argv[]说白了就是一个从程序外部获取参数的桥…

【模糊集合】示例

【模糊集合】隶属函数、关系与运算 例1 设&#xff0c; 分别进行交、并、补运算&#xff0c;有&#xff1a; 由上模糊集合的全体组成的集合称为的模糊幂集&#xff0c;记为&#xff0c;fuzzy 上述为模糊集合的Zadeh记法&#xff0c;其中的“”号不表示分式求和&#xff0c;仅作…

【绿色碳中和】工作报告词频分析—绿色环保词频数据(2001-2024)

数据简介&#xff1a;随着经济的发展和工业产业的腾飞&#xff0c;人们更多的从关注经济发展走向可持续生态经济发展&#xff0c;我国也于2020年9月22日在第七十五届联合国大会上提出了碳达峰、碳中和的目标。随着碳市场的建立和逐步完善&#xff0c;越来越多的政策与绿色环保概…

Qt 鼠标滚轮示例

1.声明 void wheelEvent(QWheelEvent *event) override;2.实现&#xff08;方便复制、测试起见用静态变量&#xff09; #include <mutex> void MainWindow::wheelEvent(QWheelEvent *event) {static QLabel *label new QLabel("Zoom Level: 100%", this);st…

开发知识点-python-Tornado框架

介绍 Tornado是一个基于Python语言的高性能Web框架和异步网络库&#xff0c;它专注于提供快速、可扩展和易于使用的网络服务。由于其出色的性能和灵活的设计&#xff0c;Tornado被广泛用于构建高性能的Web应用程序、实时Web服务、长连接的实时通信以及网络爬虫等领域。 Torna…

一命通关差分

本章节是前缀和的延申 一命通关前缀和-CSDN博客https://blog.csdn.net/qq_74260823/article/details/136530291?spm1001.2014.3001.5501 一命通关前缀和 公交车 引入 还是利用我们在前缀和中所采用的例子——公交车。 有一辆公交车&#xff0c;一共上下了N批乘客&#xff1a…