【C++项目】Rpc通信框架设计
目录
Rpc远程调用的思想
项目框架设计
服务端模块划分
网络通信模块 Network
应用层通信协议模块 Protocol
消息分发处理模块 Dispatcher
远程调用路由功能模块 RpcRouter
编辑
发布订阅功能模块 Publish-Subscribe
服务注册/发现/上线/下线功能模块 Registry-Discovery
服务端模块 Server
客户端模块划分
网络通信模块 Network
应用层通信协议模块 Protocol
消息分发处理模块 Dispatcher
请求管理模块 Requestor
远程调用功能模块 RpcCaller
发布订阅功能模块 Publish-Subscribe
服务注册/发现/上线/下线功能模块 Registry-Discovery
框架设计
抽象层
具象层
业务层
Rpc远程调用的思想
节省本地计算机的算力,通过远程调用服务器方法来实现,但是这种多对一的方法(如下图)存在一个健壮性问题,当远程服务器出现故障,所有客户端将无法正常调用方法。
因此我们需要引入分布式架构的rpc,我们因该将客户端和服务器之间的关系改为多对多的关系,以此来提高健壮性和稳定性。
如下,引入一个中转中心,进行服务发现和服务注册:
当然,客户端与这个中转中心服务器也形成了多对一的关系,但是我们可以通过升级某个rpc服务器,使其当作备用中转中心服务器,这样系统的健壮性和稳定性便有了保障。
所谓的服务发布订阅,也就是一个客户端提供某种服务,便在服务器上注册一个,也就是服务注册,服务器按功能划分主题,当一个客户端需要某个功能,就订阅哪个某个功能对应的主题,如下图:
那么客户端如何知道服务端有哪些功能主题呢?这里就需要引入服务发现,客户端先通过服务发现来发现服务器上有哪些功能主题,然后按需订阅。
这个项目的三个主要功能:
- rpc调用
- 服务注册与发现以及服务的下线/上线通知
- 消息的发布订阅
项目框架设计
服务端模块划分
服务端的功能需求:
- 基于网络通信接收客户端的请求,提供rpc服务。
- 基于网络通信接收客户端的请求,提供服务注册与发现,服务上线与下线通知。
- 基于网络通信接收客户端的请求,提供主题操作(创建/删除/订阅/取消订阅),消息发布。
我们按服务端的功能需求,将服务端的功能划分为以下几个模块:
- Network:网络通信模块
- Protocol:应用层通信协议模块
- Dispatcher:消息分发处理模块
- RpcRouter:远程调用路由功能模块
- Publish-Subscribe:发布订阅功能模块
- Registry-Discovery:服务注册/发现/上线/下线功能模块
- Server:基于以上模块整合而出的服务端模块
网络通信模块 Network
该模块为网络通信模块,实现底层的网络通信功能,使用Muduo库来进行搭建。
应用层通信协议模块 Protocol
应用层通信协议模块存在的意义:解析数据,解决通信中可能存在的粘包的问题,能够获取一条完整的消息。
该模块就是网络通信模块的设计,在网络通信中,我们是基于Tcp协议的,可能会存在粘包问题,因此我们必须设计一个应用层的网络通信协议,解决粘包问题又三种方式:特殊字符间隔(要处理转义问题)、定长(本项目中的消息有长也有短,不适合)、LV格式。这里我们使用LV格式来定义应用层的通信协议格式,如下:
首先是定长的长度(Length),变长的主体,主体又分为两大部分:
- 消息的类型(MType)(本项目使用数字来表示消息的类型,因此只需要4字节)
- 描述消息ID部分(IDLength、MID、Body)
消息的ID(每一条消息都有对应的ID,具有唯一性,客户端接收到返回的服务响应消息ID要与请求的消息ID对应,以此区分不同的服务响应)
因为消息的ID需要具有唯一性,因此我们这里ID使用字符串进行表示,因此需要三个部分表示,为了方便扩展,这里ID使用变长的,使用IDLength描述MID的长度,而MID是描述消息的ID的长度。
消息分发处理模块 Dispatcher
消息分发处理模块存在的意义:区分消息类型,根据不同的类型,调用不同的业务处理函数进行消息处理。(发出对应的rpc请求)
该模块主要是一个表,描述消息的类型和对应的回调函数,将这两者之间进行映射。
Protocol模块的onMessage接口是对接收原生的数据进行应用层协议的处理,并将获取的完整的消息内容交给Dispatcher模块,Dispatcher模块的onMessage接口来区分是什么消息类型和对应的业务处理函数(也就是查看map),然后再调用muduo库中的onMessageCallback接口。
而Dispatcher模块中通过registerHandler()接口来注册消息类型和回调函数之间的映射关系。
消息的类型:
- rpc请求和响应
- 服务注册/发现/上线/下线请求和响应
- 主题创建/删除/订阅/取消订阅请求和响应,消息发布的请求和响应
远程调用路由功能模块 RpcRouter
RpcRouter模块存在的意义:提供rpc请求的处理回调函数,内部所要实现的功能,分辨出客户端请求的服务进行处理得到结果进行响应。()
rpc请求中,最关键的两个点:
- 请求方法名称
- 请求对应要处理的参数信息
在一个rpc请求中,一定会有对应字段描述消息所请求的方法名称和相应的参数,这个模块主要是根据请求中的方法去调用对应的远程方法。
Dispatcher模块只是区分消息类型,比如服务注册..根据消息类型发送相应的rpc请求,RpcRouter模块则需要根据Dispatcher模块发来的请求中,根据方法名调用对应的远程方法,也就是说,RpcRouter模块也会有一张表表示方法与远程方法的映射关系,如下:
再因为,可能客户端发来请求中的参数不一定是正确的,所以RpcRouter模块还需要有一个方法描述,描述方法类型和参数字段名称和类型,再接收到客户端的rpc请求后,根据方法描述进行校验,没有问题则取出指定字段进行处理并返回结果。
不管是客户端要传递给服务端的服务名称以及参数信息,或者是服务端返回的结果,都是在上边Protocol中定义的Body字段中,因此Body字段就存在了一个正文的序列化/反序列化过程。
序列化的方法有很多种,这里我们使用json序列化来进行,所定义格式如下:
//RPC-request
{"method" : "Add","parameters" : {"num1" : 11,"num2" : 22}
}
//RPC-response
{"rcode" : OK,"result": 33
}
{"rcode" : ERROR_INVALID_PARAMETERS
}
根据上面所述,再实现该模块时,必须具备以下几个部分:
- 该模块必须具备一个rpc路由管理,其中包含对于每个服务的参数校验功能
- 该模块必须具备一个方法名称和方法业务回调的映射。
- 该模块必须向外提供rpc请求的业务处理函数。
发布订阅功能模块 Publish-Subscribe
Publish-Subscribe模块存在的意义:针对发布订阅请求进行处理,提供一个回调函数设置给Dispatcher模块。
该模块主要给客户端提供服务,进行主题的相关操作和消息发布。
发布订阅所包含的请求操作:
- 主题的创建
- 主题的删除
- 主题的订阅
- 主题的取消订阅
- 主题消息的发布
相应的请求和响应格式如下:
//Topic-request
{"key" : "music", //主题名称// 主题操作类型"optype" : TOPIC_CRAETE/TOPIC_REMOVE/TOPIC_SUBSCRIBE/TOPIC_CANCEL/TOPIC_PUBLISH,//TOPIC_PUBLISH请求才会包含有message字段"message" : "Hello World"
}
//Topic-response
{"rcode" : OK
}
{"rcode" : ERROR_INVALID_PARAMETERS
}
1、该模块必须具备一个主题管理,且主题中需要保存订阅了该主题的客户端连接。
- 主题收到一条消息,需要将这条消息推送给订阅了该主题的所有客户端。
2、该模块必须具备一个订阅者管理,且每个订阅者描述中必须保存自己所订阅的主题名称。
- 目的是为了当一个订阅客户端断开连接时,能够找到订阅信息的关联关系,在主题管理中进行删除。
3、该模块必须向外提供 主题创建/销毁,主题订阅/取消订阅,消息发布处理的业务处理函数。
服务注册/发现/上线/下线功能模块 Registry-Discovery
该模块主要给服务端提供服务,进行服务注册与发现。
Registry-Discovery模块存在的意义:就是针对服务注册与发现请求的处理。
- 服务注册/发现类型请求中的详细划分
- 服务注册:服务provider告诉中转中心,自己能提供哪些服务
- 服务发现:服务caller询问中转中心,谁能提供指定服务
- 服务上线:在一个provider上线了指定的服务后,通知发现过该服务的客户端有个provider可以提供该服务
- 服务下线:在一个provider断开连接,通知发现过该服务的caller,谁下线了哪个服务
//RD--request
{//SERVICE_REGISTRY-Rpc-provider进⾏服务注册//SERVICE_DISCOVERY - Rpc-caller进⾏服务发现//SERVICE_ONLINE/SERVICE_OFFLINE 在provider下线后对caller进⾏服务上下线通知"optype" : SERVICE_REGISTRY/SERVICE_DISCOVERY/SERVICE_ONLINE/SERVICE_OFFLINE,"method" : "Add",//服务注册/上线/下线有host字段,发现则⽆host字段"host" : {"ip" : "127.0.0.1","port" : 9090}
}
//Registry/Online/Offline-response
{"rcode" : OK,
}
//error-response
{"rcode" : ERROR_INVALID_PARAMETERS,
}
//Discovery-response
{"method" : "Add","host" : [{"ip" : "127.0.0.1","port" : 9090},{"ip" : "127.0.0.2","port" : 8080}]
}
该模块的设计如下:
1、必须具备一个服务发现者管理:
- 方法与发现者:当一个客户端进行服务发现的时候,进行记录谁发现过该服务,当有新的提供者上线的时候,可以通知该发现者。
- 连接与发现者:当一个发现者断开连接了,删除上面方法与发现者的关联关系,往后就不再通知了。
2、必须具备一个服务提供者管理:
- 连接与服务提供者:当一个服务提供者断开连接的时候,能够通知该提供者提供的服务(可能有多个服务)对应的发现者,该提供者提供的某某服务下线了。
- 方法与服务提供者:能够知道谁的哪些方法下线了,然后通知发现过该方法的客户端。
服务端模块 Server
该模块即能搭建一个服务注册中心,也能搭建一个服务提供者的服务器。
客户端模块划分
我们将客户端划分为以下几个功能模块:
- Network:网络通信模块
- Protocol:应用层通信协议模块
- Dispatcher:消息分发处理模块
- Requestor:请求管理模块
- RpcCaller:远程调用功能模块
- Publish-Subscribe:发布订阅功能模块
- Registry-Discovery:服务注册/发现/上线/下线功能模块
- Server:基于以上模块整合而出的服务端模块
网络通信模块 Network
网络通信基于muduo库实现网络通信客户端。
应用层通信协议模块 Protocol
应用层通信协议处理,与服务端保持一致。
消息分发处理模块 Dispatcher
IO数据分发处理,逻辑与服务端一致,与服务端的区别在于主要针对响应分发进行处理。
请求管理模块 Requestor
Requestor模块存在的意义:针对客户端的每一条请求进行管理,以便于对请求对应的响应做出合适的操作。
为什么客户端需要增加这个模块呢?
第一点:对于客户端来说,更多时候客户端是请求方,是主动发起请求服务的一方,在多线程的网络通信中,针对多个请求进行响应就可能会存在时序的问题,这种情况下,我们无法保证一个线程发送一个请求后,接下来接收到的响应就是针对自己这条请求的响应。
第二点:因为本项目是基于muduo库这种异步IO网络通信库的,通常IO都是异步操作,即发送数据就是把数据放入缓冲区,但是什么时候发送由底层的网络库来进行协调,并且也不会提供recv接口,而是在连续触发可读事件后,IO读取数据完成后调用处理回调进行数据处理,因此也无法直接在发送请求后去等待该条请求的响应。
针对以上两个问题,我们就需要创建当前的请求管理模块 Requestor,就是给每个请求都设定一个请求ID,服务器进行响应的时候标识响应针对的是哪个请求(也就是响应信息中会包含请求ID),因此客户端这边,我们不管收到哪条请求的响应,将数据存储入一个hash_map中,以请求ID作为映射,并向外提供获取指定请求ID响应的阻塞接口,这样只要在发送请求的时候知道自己的请求ID,那么就能获取到自己想要的响应,而不会出现张冠李戴的情况。
针对这个解决方法,我们再进一步,可以将每个请求进一步封装描述,添加入异步的future控制,或者设置回调函数的方式,这样不仅可以阻塞获取响应,也可以实现异步获取响应以及回调处理响应。
远程调用功能模块 RpcCaller
RpcCaller模块存在的意义:向用户提供进行rpc调用的模块。
该模块相对简单,只需要向外提供几个rpc调用的接口,内部实现向服务端发送请求,等待获取结果即可,稍微麻烦的一点是rpc调用我们需要提供多种不同方式的调用:
- 同步调用:发送调用后,等收到响应结果后返回。
- 异步调用:发起调用后立即返回,在想获取结果的时候进行获取。
- 回调调用:发起调用的同时设置结果的处理回调,收到响应后,自动对结果进行回调处理。
请求是通过Requestor模块进行发送,Requestor模块可以对收到的响应进行处理,根据请求描述区分同步/异步/回调请求进行设置相应的内容。
发布订阅功能模块 Publish-Subscribe
Publish-Subscribe模块存在的意义:向用户提供发布订阅所需的接口,针对推送过来的消息进行处理。
发布订阅稍微复杂一点,在发布订阅中,客户端可能是消息的发布者,也可能是消息的订阅者。而且不管是哪个角色都是对主题进行操作,因此也包含了主题的相关操作,比如:要发布一条消息需要先创建一个主题。
一个订阅者可能会订阅多个主题,每个主题的消息可能有不同的处理方式,因此需要有订阅者主题回调的管理。
主题创建/销毁/订阅/取消订阅,都是客户端的主动请求,但是消息发布到服务器后,对于客户端A是一个主动请求,但是对于订阅了该主题的客户端B是一个被动请求。
因此当一个客户端订阅主题的时候,就必须设置一个主题消息的处理回调。同样的,客户端也必须针对消息发布请求做出Dispatcher模块的处理分发。
Dispatcher模块中,主动的请求都是通过requestor接口进行发送的和接收处理响应的,如果是收到一个消息发布的请求,则是通过onPublish接口。
服务注册/发现/上线/下线功能模块 Registry-Discovery
- 每个服务提供端都包含一个RpcProvider服务端和RegisteryClient客户端。
- 每一个客户端都包含一个发现客户端和rpccaller客户端。
作为服务操作的客户端:
- 向外提供服务注册的功能接口:连接注册中心,发送服务注册请求,等待响应判断是否注册成功。
- 向外提供服务发现的功能接口:连接注册中心,发送服务发现请求,等待响应获取到提供服务的主机信息。
也就是说要实现的客户端,既能用于provider进行服务注册也能用于caller进行服务发现。
对于服务发现来说,注册中心只能将当前注册了该服务的主机地址返回,如果后续又有了其他的主机注册了该服务,之前进行了服务发现的主机是得不到这个主机信息的,因此还得有服务上线/下线通知。
框架设计
在本项目的实现中,我们将整个项目的实现划分为三层来进行实现
- 抽象层:将底层的网络通信以及应用层通信协议以及请求响应进行抽象,使项目更具扩展性和灵活性。
- 具象层:针对抽象的功能进行具体的实现。
- 业务层:基于抽象的框架在上层实现项目所需功能。
抽象层
在项目实现中:
- 网络通信部分采用了第三方库Muduo库
- 通信协议使用了LV格式的通信心意来解决粘包问题
- 数据正文采用了Json格式进行序列化和反序列化
而这几个方面我们后续可能会存在优化的的问题,甚至在序列化部分不一定非要采用Json,因此在设计项目框架的时候,我们对底层通信部分相关功能先进行抽象,形成一层抽象层,而上层业务部分根据抽象层来完成功能,这样的好处是在具体的底层功能实现部分,我们可以实现插拔式模块化替换,以此来提高项目的灵活性和扩展性。
具象层
具象层就是针对抽象的具体实现。
而具体的实现也比较简单,从抽象类派生出具体功能的派生类,然后在内部实现各个接口功能即可。
- 基于Muduo库实现网络通信部分抽象
- 基于LV通信协议实现Protocol部分抽象
这一层比较特殊的是:需要针对不同的请求,从BaseMessage中派生出不同的请求和响应类型,以便于在针对指定消息处理时,能够轻松的获取或设置请求及响应中的各项数据元素。
业务层
业务层就是基于底层的通信框架,针对项目中具体的业务功能的实现了,比如Rpc请求的处理,发布订阅请求的处理以及服务注册与发现的处理等等。
相关文章:

【C++项目】Rpc通信框架设计
目录 Rpc远程调用的思想 项目框架设计 服务端模块划分 网络通信模块 Network 应用层通信协议模块 Protocol 消息分发处理模块 Dispatcher 远程调用路由功能模块 RpcRouter 编辑 发布订阅功能模块 Publish-Subscribe 服务注册/发现/上线/下线功能模块 Registry-Disc…...
八股取士--dockerk8s
一、Docker 基础 Docker 和虚拟机的区别是什么? 答案: 虚拟机(VM):虚拟化硬件,每个 VM 有独立操作系统,资源占用高,启动慢。Docker:容器化应用,共享宿主机内核…...
Autojs: 使用 SQLite
例子 let db new SQLiteUtil("/sdcard/A_My_DB/sqlite.db");db.fastCreateTable("user_table",{name: "",online: false,},["name"] // 设置 name 为唯一, 重复项 不会添加成功 );// 新增数据的 ID let row_id db.insert("use…...
思科、华为、H3C常用命令对照表
取消/关闭 思科no华为undo华三undo 查看 思科show华为display华三display 退出 思科exit华为quit华三quit 设备命名 思科hostname华为sysname华三sysname 进入全局模式 思科enable、config terminal华为system-view华三system-view 删除文件 思科delete华为delete华…...

解决 `pip is configured with locations that require TLS/SSL` 错误
问题描述 在使用 pip 安装 Python 包时,可能会遇到以下错误: WARNING: pip is configured with locations that require TLS/SSL, however the ssl module in Python is not available.这意味着 Python 的 ssl 模块未正确安装或配置,导致 p…...

2025-arXiv-OmniThink:通过思考扩展机器写作的知识边界
arXiv | https://arxiv.org/abs/2501.09751 GitHub | https://github.com/zjunlp/OmniThink 项目主页 | https://zjunlp.github.io/project/OmniThink/ ModelScope 在线 Demo | https://www.modelscope.cn/studios/iic/OmniThink 摘要: 大语言模型驱动的机器写作通…...

【广州大学主办,发表有保障 | IEEE出版,稳定EI检索,往届见刊后快至1个月检索】第二届电气技术与自动化工程国际学术会议 (ETAE 2025)
第二届电气技术与自动化工程国际学术会议 (ETAE 2025) The 2nd International Conference on Electrical Technology and Automation Engineering 大会官网:http://www.icetae.com/【更多详情】 会议时间:2025年4月25-27日 会议地点:…...

机器学习:01数学基础教程
函数 极限 按照一定次数排列的一列数:“,“,…,"…,其中u 叫做通项。 对于数列{Un}如果当n无限增大时,其通项无限接近于一个常数A,则称该数列以A为极限或称数列收敛于A,否则称数列为发散, 极限值 左…...

仿叮咚买菜鸿蒙原生APP
# DingdongShopping 这是一个原生鸿蒙版的仿叮咚买菜APP项目 鸿蒙Next发布至今已经有一年多的时间了,但有时候我们想要实现一些复杂的功能或者效果,在开发文档上查阅一些资料还是比较费时的,有可能还找不到我们想要的内容。而社会层面上分享…...

WordPress“更新失败,响应不是有效的JSON响应”问题的修复
在使用WordPress搭建网站时,许多人在编辑或更新文章时,可能会遇到一个提示框,显示“更新失败,响应不是有效的JSON响应”。这个提示信息对于不了解技术细节的用户来说,太难懂。其实,这个问题并不复杂&#x…...
kotlin的onFailure: () -> Unit
在Kotlin中,onFailure: () -> Unit表示一个没有参数且返回类型为Unit的函数。 在Kotlin中,Unit类型用于表示那些没有返回值的函数。具体来说,() -> Unit表示一个没有参数的函数,其返回类型为Unit。这种函数通常用于表示…...

通过网线将Keysight DSOX4154A示波器信号传输至电脑的Step
一、硬件连接 连接网线 使用标准以太网线(Cat5e或更高)连接示波器背面的 LAN端口 至电脑或同一局域网的交换机/路由器。 二、示波器网络配置 进入网络设置菜单 点击示波器前面板右上角 【Utility】 → 【I/O】 → 【LAN Settings】。 配置IP地址 自…...

midjourney 一 prompt 提示词
midjourney 不需要自然语言的描述,它只需要关键词即可。 一个完整的Midjourney prompt通常包括三个部分 图片提示(Image Prompts)、文本提示(Text Prompt)和参数(Parameters)。 1、图片提示(…...
微信小程序 - 网络请求基础路径集中管理(基础路径集中管理策略、动态切换基础路径)
一、基础路径集中管理 在微信小程序项目开发中,经常会将请求的基础路径集中管理 这样可以避免在多个页面中重复定义,同时也方便后续维护与修改 二、基础路径集中管理策略 1、使用全局变量 微信小程序提供了 App 对象,可以在 app.js 中定义…...
C#的委托delegate与事件event
在C#中,delegate(委托)和 event(事件)是两个非常重要的概念,它们主要用于实现回调机制和事件驱动编程。下面详细介绍它们的原理和使用场景。 1. Delegate(委托) 1.1 委托的原理 委托…...
apache artemis安装
安装apache artemis https://xxzkid.github.io/2025/apache-artemis-install...

Lightning基础训练尝试实例
一、训练任务概述 动机:由于后续的课题中会用到类似图像去噪的算法,考虑先用U-Net,这里做一个前置的尝试。 训练任务:分割出图像中的细胞。 数据集:可私 数据集结构: 二、具体实现 U-Net的网络实现是现…...
osgearth视点坐标及鼠标交点坐标的信息显示(七)
核心函数如下: void COSGObject::addViewPointLabel() {//mRoot->addChild(osgEarth::Util::Controls::ControlCanvas::get(mViewer));//放开这句,球就卡住了。 为什么,shitosgEarth::Util::Controls::ControlCanvas* canvas = osgEarth::Util::Controls::ControlCanvas…...

动态规划 之 背包问题
文章目录 0-1背包问题2915.和为目标值的最长子序列的长度494.目标和 完全背包问题322.零钱兑换518.零钱兑换II 多重背包2585.获得分数的方法数 分组背包1155.掷骰子等于目标和的方法数 背包问题是动态规划一个很重要的一类题目,主要分为0-1背包问题以及完全背包问题…...

【Azure 架构师学习笔记】- Azure Databricks (11) -- UC搭建
本文属于【Azure 架构师学习笔记】系列。 本文属于【Azure Databricks】系列。 接上文 【Azure 架构师学习笔记】- Azure Databricks (10) – UC 使用 前言 由于ADB 的更新速度很快,在几个月之后重新搭建ADB 时发现UC 已经更新了很多,为了后续做ADB 的功…...

深度学习在微纳光子学中的应用
深度学习在微纳光子学中的主要应用方向 深度学习与微纳光子学的结合主要集中在以下几个方向: 逆向设计 通过神经网络快速预测微纳结构的光学响应,替代传统耗时的数值模拟方法。例如设计超表面、光子晶体等结构。 特征提取与优化 从复杂的光学数据中自…...

XCTF-web-easyupload
试了试php,php7,pht,phtml等,都没有用 尝试.user.ini 抓包修改将.user.ini修改为jpg图片 在上传一个123.jpg 用蚁剑连接,得到flag...
多场景 OkHttpClient 管理器 - Android 网络通信解决方案
下面是一个完整的 Android 实现,展示如何创建和管理多个 OkHttpClient 实例,分别用于长连接、普通 HTTP 请求和文件下载场景。 <?xml version"1.0" encoding"utf-8"?> <LinearLayout xmlns:android"http://schemas…...
Java多线程实现之Callable接口深度解析
Java多线程实现之Callable接口深度解析 一、Callable接口概述1.1 接口定义1.2 与Runnable接口的对比1.3 Future接口与FutureTask类 二、Callable接口的基本使用方法2.1 传统方式实现Callable接口2.2 使用Lambda表达式简化Callable实现2.3 使用FutureTask类执行Callable任务 三、…...

新能源汽车智慧充电桩管理方案:新能源充电桩散热问题及消防安全监管方案
随着新能源汽车的快速普及,充电桩作为核心配套设施,其安全性与可靠性备受关注。然而,在高温、高负荷运行环境下,充电桩的散热问题与消防安全隐患日益凸显,成为制约行业发展的关键瓶颈。 如何通过智慧化管理手段优化散…...
JS设计模式(4):观察者模式
JS设计模式(4):观察者模式 一、引入 在开发中,我们经常会遇到这样的场景:一个对象的状态变化需要自动通知其他对象,比如: 电商平台中,商品库存变化时需要通知所有订阅该商品的用户;新闻网站中࿰…...

深度学习水论文:mamba+图像增强
🧀当前视觉领域对高效长序列建模需求激增,对Mamba图像增强这方向的研究自然也逐渐火热。原因在于其高效长程建模,以及动态计算优势,在图像质量提升和细节恢复方面有难以替代的作用。 🧀因此短时间内,就有不…...
Linux系统部署KES
1、安装准备 1.版本说明V008R006C009B0014 V008:是version产品的大版本。 R006:是release产品特性版本。 C009:是通用版 B0014:是build开发过程中的构建版本2.硬件要求 #安全版和企业版 内存:1GB 以上 硬盘…...

MySQL的pymysql操作
本章是MySQL的最后一章,MySQL到此完结,下一站Hadoop!!! 这章很简单,完整代码在最后,详细讲解之前python课程里面也有,感兴趣的可以往前找一下 一、查询操作 我们需要打开pycharm …...
Python实现简单音频数据压缩与解压算法
Python实现简单音频数据压缩与解压算法 引言 在音频数据处理中,压缩算法是降低存储成本和传输效率的关键技术。Python作为一门灵活且功能强大的编程语言,提供了丰富的库和工具来实现音频数据的压缩与解压。本文将通过一个简单的音频数据压缩与解压算法…...