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://www.mzph.cn/news/751460.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【C++刷题】优选算法——动态规划第一辑

1.状态表示是什么&#xff1f;简答理解是dp表里的值所表示的含义怎么来的&#xff1f;题目要求经验题目要求分析问题的过程中&#xff0c;发现重复子问题 2.状态转移方程dp[i]......细节问题&#xff1a;3.初始化控制填表的时候不越界4.填表顺序控制在填写当前状态的时候&#…

腾讯云免费服务器配置大全和个人企业申请流程,2024年新版教程

腾讯云免费服务器申请入口 https://curl.qcloud.com/FJhqoVDP 免费服务器可选轻量应用服务器和云服务器CVM&#xff0c;轻量配置可选2核2G3M、2核8G7M和4核8G12M&#xff0c;CVM云服务器可选2核2G3M和2核4G3M配置&#xff0c;腾讯云服务器网txyfwq.com分享2024年最新腾讯云免费…

蓝桥杯每日一题——棋盘

问题描述 小蓝拥有 n xn 大小的棋盘&#xff0c;一开始棋盘上全都是白子。小蓝进行了 m 次操作&#xff0c;每次操作会将棋盘上某个范围内的所有棋子的颜色取反(也就是白色棋子变为黑色&#xff0c;黑色棋子变为白色)请输出所有操作做完后棋盘上每个棋子的颜色。输入格式 输入的…

卷积神经网络算法原理(卷积层,卷积运算,填充,步幅,经过卷积运算后的特征图大小,池化层,最大池化,平均池化,经过池化层运算后的特征图大小)

文章目录 卷积神经网络算法原理(卷积层&#xff0c;卷积运算&#xff0c;填充&#xff0c;步幅&#xff0c;经过卷积运算后的特征图大小&#xff0c;池化层&#xff0c;最大池化&#xff0c;平均池化&#xff0c;经过池化层运算后的特征图大小)前言1、图像的本质1.1、灰度图1.2…

Java学习笔记(16)

常见算法 查找算法 查询某个元素是否存在 二分查找&#xff08;数组元素必须是有序的&#xff09; package exercise;public class exercise1 {public static void main(String[] args) {int[] arr {7, 23, 797, 23, 79, 81, 103, 127, 131, 147};System.out.println(binar…

实战Python Socket编程:开发多用户聊天应用

实战Python Socket编程&#xff1a;开发多用户聊天应用 Python Socket 编程概述什么是Socket编程&#xff1f;Socket编程的应用场景Socket编程的重要性基本概念 环境准备Python版本必要的库开发环境配置调试工具 基本Socket编程创建Socket绑定Socket到端口监听连接接受连接发送…

24.第12届蓝桥杯省赛真题题解

A.空间&#xff08;100%&#xff09; 计算机存储单位计算 1TB2^10 GB 1GB2^10 MB 1MB2^10 KB 1KB2&10 B 1B8 bit(bit位二进制的最小的存储单位) #include <iostream> #include <cmath>using namespace std; //2^28B 2^2int main(){std::ios::sync_with_stdio…

【C语言入门】浮点型数据在内存中的存储

✨✨欢迎大家来到Celia的博客✨✨ &#x1f389;&#x1f389;创作不易&#xff0c;请点赞关注&#xff0c;多多支持哦&#x1f389;&#x1f389; 所属专栏&#xff1a;C语言 个人主页&#xff1a;Celias blog~ 目录 ​编辑 引言 引例 一、浮点型在内存中的存储方式 1.1 …

在idea中配置tomcat服务器,然后部署一个项日

1.下载tomcat Tomcat下载 点击右边的tomcat8 找到zip点击下载 下载完&#xff0c;解压到你想放置的路径下 2.配置环境变量 打开设置找到高级系统设置点击环境变量 点击新建&#xff0c;变量名输入&#xff1a;CATALINA_HOME&#xff0c;变量值就是Tomcat的安装路径&#x…

【QT+QGIS跨平台编译】之七十七:【QGIS_Gui跨平台编译】—【错误处理:字符串错误】

文章目录 一、字符串错误二、处理方法三、涉及到的文件一、字符串错误 常量中有换行符错误:(也有const char * 到 LPCWSTR 转换的错误) 二、处理方法 需要把对应的文档用记事本打开,另存为 “带有BOM的UTF-8” 三、涉及到的文件 src\gui\qgsadvanceddigitizingdockwidge…

智慧礼金:电子礼金薄,让礼薄更添智能,你确定不进来看看?

智慧礼金&#xff1a;电子礼金薄&#xff0c;让礼薄更添智能&#xff0c;你确定不进来看看&#xff1f; 一、重要声明二、相关介绍三、使用好处四、如何找到该小程序 随着科技的不断进步&#xff0c;传统的纸质礼金簿已经逐渐被电子化管理所取代。今天&#xff0c;我们要向大家…

Java解决完全二叉树的节点个数

Java解决完全二叉树的节点个数 01 题目 给你一棵 完全二叉树 的根节点 root &#xff0c;求出该树的节点个数。 完全二叉树 的定义如下&#xff1a;在完全二叉树中&#xff0c;除了最底层节点可能没填满外&#xff0c;其余每层节点数都达到最大值&#xff0c;并且最下面一层的…

1990-2022年各省全要素生产率数据(仅结果)

1990-2022年各省全要素生产率数据&#xff08;仅结果&#xff09; 1、时间&#xff1a;1990-2022年 2、指标&#xff1a;地区、年份、OLS、FE、RE、DGMM、SGMM、SFA1、SFA2、SFA3、SFA3D、TFE、非参数法 3、范围&#xff1a;31省 4、计算说明&#xff1a; 产出指标&#x…

【自动化测试】如何在jenkins中搭建allure

相信大家在做自动化测试过程中&#xff0c;都会用到自动化测试环境&#xff0c;目前最常见的就是通过容器化方式部署自动化测试环境&#xff0c;但对于一些测试小白&#xff0c;不是很会搭建持续集成环境&#xff0c;特别是从0-1的过程&#xff0c;需要自行搭建很多依赖环境&am…

奇数乘积(C语言)

一、运行结果&#xff1b; 二、源代码&#xff1b; # define _CRT_SECURE_NO_WARNINGS # include <stdio.h>int main() {//初始化变量值&#xff1b;int i 1;int j 3;//循环运算&#xff1b;while (j < 12){//运算&#xff1b;i i * j;//改变数值&#xff1b;j 2…

rt-thread之通讯协议modbus软件包的使用记录(lwip+modbus组合)

前言 使用freemodbus软件包使用网口通讯(sallwip)ip地址使用dhcp动态获取 软件包 相关宏定义 /*-----------------------------------------NET 宏定义-------------------------------------------*/#define RT_USING_SAL #define SAL_INTERNET_CHECK /* Docking with prot…

前端框架vue的样式操作,以及vue提供的属性功能应用实战

✨✨ 欢迎大家来到景天科技苑✨✨ &#x1f388;&#x1f388; 养成好习惯&#xff0c;先赞后看哦~&#x1f388;&#x1f388; &#x1f3c6; 作者简介&#xff1a;景天科技苑 &#x1f3c6;《头衔》&#xff1a;大厂架构师&#xff0c;华为云开发者社区专家博主&#xff0c;…

【Linux】环境基础开发工具使用

目录 Linux软件管理器 yum 1.什么是软件包 2.查看软件包 3安装与卸载 vim-Linux编辑器 1.vim基础概念 2.vim的基础操作 命令模式基本操作 底层模式基本操作 3、其它模式 Linux编译器 gcc/g 1.如何进行编译 2.编译的四个过程 预处理(-E) 编译(-S) 汇编(-c) 链接…

python二级备考(2)-简单应用题

第1套 使用turtle库的turtle. right()函数和turtle.fd()函数绘制一个菱形&#xff0c;边长为200像素&#xff0c;4个内角度数为2个60度和2个120度 键盘输入一组人员的姓名、性别、年龄等信息&#xff0c;信息间采用空格分隔&#xff0c;每人一行&#xff0c;空行回车结束录入&a…

EMQX 实践

MQTT 核心概念 发布订阅 MQTT 基于发布订阅模式&#xff0c;它解耦了消息的发送方&#xff08;发布者&#xff09;和接收方&#xff08;订阅者&#xff09;&#xff0c;引入了一个中间代理的角色来完成消息的路由和分发。发布者和订阅者不需要知道彼此的存在&#xff0c;他们…