2、python进程间通信方案设计

简介: 解决进程间各功能类之间的通信问题。

3.进程间通信方案

3.1方案一:类UDP通信

3.1.1设计思路

由于工具将界面和任务处理进行了分离,因此,工具的整体框架可以看成是由客户端和服务器组成,客户端发送请求,服务器响应请求并返回结果。

客户端即界面,用户在界面上操作,并最终在界面上得到操作的结果。界面由主界面和子界面组成,每个界面是一类相同任务类型的集合,如Snmp报文测试界面可以执行向设备发送snmp报文的任务,连接类界面则实现了SSHNetconf等登陆设备的方式。

服务器则由任务分发模块和任务处理模块组成,任务分发模块将请求的任务分发至对应的任务处理模块进行处理。任务处理模块的功能是执行具体的任务请求,每个模块均是一类任务类型的集合,简单来看任务处理模块和界面之间可以存在一一对应的关系,如Snmp报文测试界面存在对应的Snmp报文任务模块,连接类界面存在对应的连接类任务模块。不同的是,一类界面可能同时打开多个子界面,如连接类子界面0、连接类子界面1,而任务处理模块则只存在一个实例,处理所有子界面的任务请求。需要注意的是,实际界面和任务模块之间并不是绑定的关系,即界面的请求根据其任务类型,可以发送给多个不同的任务模块。所以服务器的任务模块需要包含所有界面中的任务请求处理程序,如果服务器收到未知的任务请求,会返回任务未定义错误信息。

image.png

1 界面和服务器

综上所诉,进程间通信需要解决的问题是,将某一界面的任务请求数据(任务请求代码和附加数据)发送至对应的任务处理模块,并且将任务处理结果返回至该界面。为了解决该问题,采用UDP通信的思想,给每个界面和任务处理模块分配一个IP,数据封装在报文中,报文包含源IP地址和目的IP地址,转发模块根据IP转发报文,达到通信的目的。

image.png

2 数据传输问题

3.1.2详细设计

image.png

1 通信设计图

一、网络结构

1、硬件结构:

(1)  硬件结构由PipeQueue组成,所有的报文均是生产者写入Pipe或者Queue,由消费者从Pipe或者Queue中读取报文,以达到报文在进程间和线程间转发的目的;

2、转发模块:

(1)  转发模块主要负责定义数据包格式和地址格式;

(2)  解析接收到的报文的地址,选择路由进行转发;

3、应用层:

(1)  发送数据的接口;

二、报文结构

1、报文由首部和数据两部分组成,首部的主要目的是标记路由信息,数据的主要目的是携带任务执行所需要的必要信息。

image.png

2 报文结构

2、如下图,首部包含源IP、目的IP、请求任务类型代码和报文编号。

image.png

3 报文首部

(1)IP:发送报文模块的IP地址;

(2)目的IP:报文的接收模块的IP地址;

(3)请求任务类型代码:任务类型大类,指定了由哪个任务处理模块处理本次任务请求,如指定连接类任务模块响应任务请求;

(4)报文编号:每条报文的唯一标识,可根据报文编号对应发送的报文和任务处理后的响应报文,报文编号由应用层自动生成;

3、数据部分由下图所示五部分组成:

image.png

4 数据结构

(1)请求任务具体类型:指定了任务处理模块中的具体任务,如连接类模块中的建立SSH连接任务;

(2)附加数据:执行任务所需的数据,如建立SSH连接任务需要设备IP、用户名和密码等数据,附加数据的数据格式由各个任务自行定义,无统一规定;

(3)任务是否成功标识:此部分由任务处理模块在响应报文中添加,标记了此次任务请求是否执行成功;

(4)任务错误信息:此部分由任务处理模块在响应报文中添加,记录任务执行过程中出现的错误信息;

(5)任务结果附加信息:此部分由任务处理模块在响应报文中添加,记录任务执行的具体结果数据,如请求向设备发送命令任务得到的设备回显信息;

4、Python实现的报文是字典类型,如下所示:

package = {

   'source_id': source_buffer_id,  

   'destination_id': destination_buffer_id,  

   'task_id': task_id,

   'msg_id': msg_id,

   'data': data

}

data = {

   'task_type': task_type0,

   'append_data': [],

'task_success': True/False,

task_type0: None,

'error_msg': error_msg

}

与报文的对应关系为:

image.png

image.png

图5 Python实现与报文的对应关系

三、程序设计

1、IP格式:

(1)  IP由两位数字组成,数字之间用_分割,如1_32

(2)  IP在局域网中是唯一的,跨局域网可能存在相同的IP

2、IP分配:

(1)  首先要确定哪些对象需要分配IP,本工具对于具体的功能类分配唯一的IP地址,功能类是一类功能实体的集合,在程序中表现为类,如各个子界面、任务处理模块;

(2)  每一类的功能模块有全局唯一的代码,作为IP的首位,此代码也是task_id的首位;

image.png

图6功能模块代码

(3)  一类界面的多个子界面IP的首位是相同的,比如两个连接类子界面的IP分别为5_05_1,即可以通过IP的首位确定是哪一类的功能模块;

(4)  将每个进程看做是一个局域网,进程启动时会分配到一个局域网IP。数据如需发送至其他进程,则报文中的目的IP需要包含局域网的IP,否则默认报文在当前局域网(进程)中转发;

(5)  子进程的IP由主进程在创建子进程时生成;

(6)  各个功能模块的IP由主线程在创建功能模块时生成;

3、路由学习:

(1)  工具的路由是静态的,主进程在创建子进程时,会将所有进程的IP信息都发送给子进程;

(2)  进程内,各个功能模块的代码存储在主线程中,供转发线程查询;

4、转发规则:

(1)  报文由报文转发线程进行转发,每个进程中只有一个转发线程,即界面程序设计方案2中的监听线程;

(2)  转发线程在接收到报文之后,首先分析目的地址:

①   目的地址只含有一个IP地址时,如果此IP地址与当前进程的IP地址相同,则分析task_id,根据task_id确定任务处理模块;

②   目的地址只含有一个IP地址时,如果此IP地址与当前进程的IP地址不同,则寻找路由进行转发;

③   目的地址包含多个IP地址时,提取首位IP,如果首位IP与当前进程IP相同,则根据第二个IP进行转发,且转发前,删除首位IP,如8_0_9_0修改为9_0

④   目的地址包含多个IP地址时,如果首位IP与当前进程IP不同,则根据首位IP进行转发;

⑤   如果找不到转发路由,则返回功能未定义错误;

(3)  如果报文需要转发到其他进程,且源IP的首位IP不是当前进程的IP,则将在'source_id'的头部加入当前进程的IP,标记报文经过了当前进程,如9_0转发后为8_0_9_0

(4)  一个报文支持多目的地址转发,所有目的地址以list的形式存放在destination_id对应的值中;

(5)  功能处理模块接收到报文之后,如果报文中的task_type未定义处理方法,则返回功能未定义错误,如果task_type已定义,则返回处理后的结果;

(6)  功能处理模块处理完请求的任务后,将接收到报文中的source_iddestination_id交换再交由转发线程转发;

(7)  当程序包含多个子进程时,子进程间的通信经由主进程实现,即子进程0的报文先发送至主进程,再由主进程转发至子进程1,目的是不需要建设过多的物理线路,简化程序设计;

(8)  传输大数据时,数据先存放在文件中,报文中只发送文件的目录地址;

5、进程间转发:

image.png

图7进程间转发

(1)  某个功能模块将待发送的数据通过报文生成模块生成原始报文,如Trap界面(集成在了监听界面)发送请求启动Trap监听的报文,

其中:

9_0:监听界面的IP

6_0:表示报文的目的地是任务中心进程:

1_2023...:请求由Trap功能模块执行任务;

0:执行的具体任务代码为0,即'start_listening'

{'source_id': '9_0', 'destination_id': '6_0', 'task_id': '1_20230321105253598910', 'msg_id': '20230321105253598564', 'data': {'task_type': 0, 'append_data': [{'port': '160', 'ipv4': True, 'ipv6': True}]}}

(2)  主进程的转发线程在接收到报文之后,由于需要转发的其他进程,在'source_id'的头部加入当前进程的IP,如上述报文处理后被转发:

{'source_id': '8_0_9_0', 'destination_id': '6_0', 'task_id': '1_20230321105253598910', 'msg_id': '20230321105253598564', 'data': {'task_type': 0, 'append_data': [{'port': '160', 'ipv4': True, 'ipv6': True}]}}

(3)  子进程接收到报文后,检查destination_id,如果目的地址就是当前进程,无下一跳地址,则分析task_id,根据task_id首位确定报文请求的服务应该发送至哪个功能模块进行处理,如上述报文将转发至Trap模块。如果功能模块未定义,则子进程返回未定义错误;

(4)  功能模块接收到报文之后,提取task_type,并在定义的服务列表中寻找该task_type,如果task_type已定义处理方法,则调用方法执行任务,处理完成后返回处理结果,如果task_type未定义,则返回未定义错误。上述报文在处理完成后返回的报文如下:

{'source_id': '6_0', 'destination_id': '8_0_9_0', 'task_id': '1_20230321105253598910', 'msg_id': '20230321105253598564', 'data': {'task_type': 0, 'append_data': [{'port': '160', 'ipv4': True, 'ipv6': True}], 'task_success': True, 'error_msg': ''}}

(5)  子进程转发线程将功能模块处理完成后的报文根据目的地址进行转发,如上述报文经过子进程转发后为:

{'source_id': '6_0', 'destination_id': '8_0_9_0', 'task_id': '1_20230321105253598910', 'msg_id': '20230321105253598564', 'data': {'task_type': 0, 'append_data': [{'port': '160', 'ipv4': True, 'ipv6': True}], 'task_success': True, 'error_msg': ''}}

(6)  主进程在接收到报文后,根据转发规则转发报文,如上述报文经过转发后为:

{'source_id': '8_0_6_0', 'destination_id': '9_0', 'task_id': '1_20230321105253598910', 'msg_id': '20230321105253598564', 'data': {'task_type': 0, 'append_data': [{'port': '160', 'ipv4': True, 'ipv6': True}], 'task_success': True, 'error_msg': ''}}

目的地址为9_0,报文将会转发到IP9_0的监听界面。

(7)  最终,处理后的报文返回到发起服务请求的界面,完成了从发起服务请求,到处理服务请求,最后返回服务请求结果的完整流程。

6、进程内转发:

image.png

图8进程内转发

进程内转发与进程间转发的差异在于报文的目的地址首位IP不指向其他进程的IP,转发线程在接收到报文后,寻找路由进行转发。其他过程与进程间转发一致。

7、主动上报:

image.png

图9事件上报

功能模块在响应任务返回结果之后,后台可能依然会存在任务执行线程,该线程会记录任务对应的源IP等信息。如果线程在执行任务过程中出现异常事件,线程会将该事件根据记录的源IP上报给请求服务的模块。如trap模块在后台持续执行监听任务过程中,如果遇到异常退出监听的事件,监听任务线程会将事件上报给监听界面,告知用户后台的任务运行情况。

3.1.3方案有效性

此方案能够实现进程内和跨进程的通信功能,且不存在丢包的情况。

3.1.4程序示例

https://github.com/AlvinsFish/UiExample

 

目录
相关文章
|
10天前
|
机器学习/深度学习 Rust 算法
Python环境管理的新选择:UV和Pixi,高性能Python环境管理方案
近期Python生态系统在包管理领域发生了重要变化,Anaconda调整商业许可证政策,促使社区寻找更开放的解决方案。本文介绍两款新一代Python包管理工具:UV和Pixi。UV用Rust编写,提供高性能依赖解析和项目级环境管理;Pixi基于Conda生态系统,支持conda-forge和PyPI包管理。两者分别适用于高性能需求和深度学习项目,为开发者提供了更多选择。
38 2
|
2月前
|
并行计算 数据处理 调度
Python中的并发编程:探索多线程与多进程的奥秘####
本文深入探讨了Python中并发编程的两种主要方式——多线程与多进程,通过对比分析它们的工作原理、适用场景及性能差异,揭示了在不同应用需求下如何合理选择并发模型。文章首先简述了并发编程的基本概念,随后详细阐述了Python中多线程与多进程的实现机制,包括GIL(全局解释器锁)对多线程的影响以及多进程的独立内存空间特性。最后,通过实例演示了如何在Python项目中有效利用多线程和多进程提升程序性能。 ####
|
2月前
|
调度 iOS开发 MacOS
python多进程一文够了!!!
本文介绍了高效编程中的多任务原理及其在Python中的实现。主要内容包括多任务的概念、单核和多核CPU的多任务实现、并发与并行的区别、多任务的实现方式(多进程、多线程、协程等)。详细讲解了进程的概念、使用方法、全局变量在多个子进程中的共享问题、启动大量子进程的方法、进程间通信(队列、字典、列表共享)、生产者消费者模型的实现,以及一个实际案例——抓取斗图网站的图片。通过这些内容,读者可以深入理解多任务编程的原理和实践技巧。
117 1
|
3月前
|
Python
Python中的多线程与多进程
本文将探讨Python中多线程和多进程的基本概念、使用场景以及实现方式。通过对比分析,我们将了解何时使用多线程或多进程更为合适,并提供一些实用的代码示例来帮助读者更好地理解这两种并发编程技术。
|
2月前
|
监控 JavaScript 前端开发
python中的线程和进程(一文带你了解)
欢迎来到瑞雨溪的博客,这里是一位热爱JavaScript和Vue的大一学生分享技术心得的地方。如果你从我的文章中有所收获,欢迎关注我,我将持续更新更多优质内容,你的支持是我前进的动力!🎉🎉🎉
30 0
|
3月前
|
数据挖掘 程序员 调度
探索Python的并发编程:线程与进程的实战应用
【10月更文挑战第4天】 本文深入探讨了Python中实现并发编程的两种主要方式——线程和进程,通过对比分析它们的特点、适用场景以及在实际编程中的应用,为读者提供清晰的指导。同时,文章还介绍了一些高级并发模型如协程,并给出了性能优化的建议。
44 3
|
4月前
|
负载均衡 Java 调度
探索Python的并发编程:线程与进程的比较与应用
本文旨在深入探讨Python中的并发编程,重点比较线程与进程的异同、适用场景及实现方法。通过分析GIL对线程并发的影响,以及进程间通信的成本,我们将揭示何时选择线程或进程更为合理。同时,文章将提供实用的代码示例,帮助读者更好地理解并运用这些概念,以提升多任务处理的效率和性能。
71 3
|
3月前
|
存储 Python
Python中的多进程通信实践指南
Python中的多进程通信实践指南
36 0
|
4月前
|
消息中间件 安全 Kafka
Python IPC机制全攻略:让进程间通信变得像呼吸一样自然
【9月更文挑战第12天】在编程领域,进程间通信(IPC)是连接独立执行单元的关键技术。Python凭借简洁的语法和丰富的库支持,提供了多种IPC方案。本文将对比探讨Python的IPC机制,包括管道与消息队列、套接字与共享内存。管道适用于简单场景,而消息队列更灵活,适合高并发环境。套接字广泛用于网络通信,共享内存则在本地高效传输数据。通过示例代码展示`multiprocessing.Queue`的使用,帮助读者理解IPC的实际应用。希望本文能让你更熟练地选择和运用IPC机制。
75 10
|
4月前
|
安全 开发者 Python
Python IPC大揭秘:解锁进程间通信新姿势,让你的应用无界连接
【9月更文挑战第11天】在编程世界中,进程间通信(IPC)如同一座无形的桥梁,连接不同进程的信息孤岛,使应用无界而广阔。Python凭借其丰富的IPC机制,让开发者轻松实现进程间的无缝交流。本文将揭开Python IPC的神秘面纱,介绍几种关键的IPC技术:管道提供简单的单向数据传输,适合父子进程间通信;队列则是线程和进程安全的数据共享结构,支持多进程访问;共享内存允许快速读写大量数据,需配合锁机制确保一致性;套接字则能实现跨网络的通信,构建分布式系统。掌握这些技术,你的应用将不再受限于单个进程,实现更强大的功能。
74 6