当前位置: 首页 > article >正文

Json-Rpc框架(项目设计 —— 服务端模块功能详细介绍)

阅读导航

  • 引言
  • 一、Network模块
  • 二、Protocol模块
  • 三、Dispatcher模块
  • 四、RpcRouter模块
  • 五、Publish-Subscribe模块
  • 六、Registry-Discovery模块
  • 七、总结Server模块

引言

在上一篇文章中,我们初步探索了Json-Rpc框架项目的整体架构,特别是服务端与客户端模块的划分与设计理念,为理解这一强大远程过程调用(RPC)机制奠定了坚实的基础。今天,我们将深入服务端模块的腹地,细致剖析其内部功能与实现细节。服务端作为Json-Rpc框架的核心组成部分,不仅负责接收并解析来自客户端的请求,还承担着业务逻辑处理、结果封装及响应回传的重任。

一、Network模块

Network模块:负责网络通信的底层实现,包括监听客户端的连接请求、数据的接收与发送等,确保服务端与客户端之间的稳定通信。

网络通信模块,作为实现底层网络通信功能的核心组件,其复杂性与重要性不言而喻。鉴于项目的庞大规模和复杂性,我们决定采用陈硕大佬的Muduo库来构建这一关键模块。Muduo库以其高效、稳定的性能在业界广受好评,并且我们之前已经对其基本使用方法进行了介绍,这将为我们快速、准确地集成该库并构建网络通信模块提供有力支持。

二、Protocol模块

Protocol模块:定义并实现应用层的通信协议,该模块负责解析和封装网络传输中的数据,确保数据的正确性和完整性,同时提供统一的接口供上层模块调用。

这个模块主要是为了解决网络通信中由于TCP的流式传输特性可能导致的粘包问题。粘包问题是指多个数据包在发送或接收过程中,可能因为网络延迟、缓冲区大小等因素被合并成一个大的数据包,或者一个数据包被分割成多个小的数据包进行传输。

为了应对粘包问题,通常可以采用以下几种策略来设计应用层协议:

  1. 特殊字符间隔:在数据包之间插入特定的分隔符,接收方通过识别这些分隔符来区分不同的数据包。这种方法实现简单,但需要注意特殊字符可能出现在数据内容中的情况,可能需要进行转义处理。

  2. 定长:每个数据包都固定长度,接收方按照固定长度来读取数据。这种方法实现简单,但灵活性较差,且可能浪费带宽(如果数据内容本身长度不一且差距较大)。

  3. LV格式(长度+值):数据包由两部分组成,首先是数据长度部分(Length),然后是实际的数据内容(Value)。接收方首先读取长度部分,然后根据长度信息读取相应长度的数据内容。这种方法既灵活又高效,是目前网络通信中较为常用的协议设计方式之一。

在定义的应用层通信协议格式中,我们采用了LV(Length-Value)结构,其中:

在这里插入图片描述

  • Length:这是一个固定长度为4字节的字段,用于明确指示紧随其后的本条消息数据的总长度,确保了数据的完整性和准确性。
  • MType:作为Value部分的一个固定字段,同样占据4字节,用于明确标识该条消息的类型。这些类型包括但不限于RPC的请求与响应消息、发布/订阅相关消息(如发布、订阅、取消订阅及消息推送)、主题管理消息(如主题的创建与删除)以及服务管理消息(如服务的注册、发现、上线与下线)。
  • IDLength:该字段也是固定的,占用4字节,用于精确描述紧接着的ID字段的实际长度,以支持不同长度的消息标识符。
  • MID:即消息ID,是每条消息中必有的一个不固定长度的字段,用于唯一标识该条消息,确保消息在传输过程中的可追溯性和唯一性。
  • Body:作为消息的主体部分,包含了请求或响应的实际内容,其长度由Length字段中指定的总长度减去前面所有固定字段和ID字段的长度来确定。

这样的设计使得通信协议既灵活又高效,能够支持多种类型的消息传输,同时确保了数据的正确解析和传输的可靠性。

三、Dispatcher模块

Dispatcher模块:作为消息分发处理中心,该模块接收来自Network模块的数据,并根据协议解析结果,将请求分发到相应的处理模块。它负责请求的路由和分发逻辑,确保每个请求都能被正确处理。

当muduo网络库在其底层通信层接收到数据时,这些数据会触发onMessage回调函数。在这个回调函数中,首先会按照应用层定义的协议对接收到的数据进行解析,以提取出完整的消息载荷。完成解析后,接下来需要确定这条消息代表了客户端的何种请求,并决定如何对其进行处理。

为此,我们设计了一个名为Dispatcher的分发模块。该模块的核心是一个hash_map(或类似的数据结构),其键(key)是消息的类型,而值(value)则是与之关联的回调函数。当Dispatcher模块接收到解析后的消息时,它会根据消息的类型在hash_map中查找对应的处理函数。一旦找到匹配的回调函数,Dispatcher就会调用该函数来处理该消息。
在这里插入图片描述

四、RpcRouter模块

RpcRouter模块:专注于RPC(远程过程调用)的路由功能,该模块接收 Dispatcher`模块分发的RPC请求,根据服务名、方法名等信息,找到对应的RPC服务提供者,并转发请求。同时,它还负责处理RPC调用的结果返回给客户端。

在RPC请求中,最为核心的两个要素是:

  1. 请求方法名称:这是客户端希望服务端执行的具体操作的标识符。客户端通过指定这个名称来告诉服务端它需要调用哪个服务或方法。

  2. 请求对应的参数信息:这些参数是执行指定方法所必需的输入数据。它们被包含在请求中,以便服务端能够正确地执行请求的方法并返回预期的结果。

在RPC的上下文中,无论是客户端发送给服务端的请求数据,还是服务端返回给客户端的响应数据,都需要通过某种协议进行封装。这里提到的Protocol中的Body字段正是用于承载这些数据的部分。由于我们讨论的是JSON-RPC,这意味着Body字段中的数据会使用JSON格式进行序列化和反序列化。(JSON用法在前面有讲到)

在这里插入图片描述

五、Publish-Subscribe模块

Publish-Subscribe模块:实现消息的发布订阅功能,包括主题的创建、删除、订阅和取消订阅操作,以及消息的发布和分发。该模块允许客户端订阅感兴趣的主题,并在有消息发布时,将消息推送给所有订阅了该主题的客户端。
在这里插入图片描述

六、Registry-Discovery模块

Registry-Discovery模块:负责服务的注册、发现、上线和下线管理。该模块维护一个服务注册表,记录所有在线服务的信息。客户端可以通过该模块查询所需服务的信息,实现服务的动态发现和调用。同时,服务提供者也可以在该模块中注册和注销自己的服务。

服务注册/发现类型请求中的详细划分

  • 服务注册:服务provider告诉中转中心,自己能提供哪些服务。
  • 服务发现:服务caller询问中转中心,谁能提供指定服务。
  • 服务上线:在一个provider上线了指定服务后,通知之前发现过该服务的客户端,告知有一个新的provider可以提供该服务。
  • 服务下线:在一个provider断开连接时,通知之前发现过该服务的caller,告知哪个provider下线了哪个服务。

服务注册模块的重要性

该模块主要是为了实现分布式架构而存在,它使得每一个RPC客户端能够从不同的节点主机上获取自己所需的服务,从而让业务更具扩展性,系统更具健壮性。而为了能够让RPC-caller知道有哪些RPC-provider能提供自己所需服务,那么就需要有一个注册中心来让这些RPC-provider去注册登记自己的服务,以便RPC-caller能够发现并调用这些服务。

在这里插入图片描述

七、总结Server模块

Server模块:作为服务端的整合模块,它基于以上各个模块构建而成,提供统一的服务端接口和启动逻辑。Server模块负责初始化各个子模块,并协调它们之间的协作,确保服务端能够正常运行并提供所需的服务。

在这里插入图片描述


http://www.kler.cn/news/360143.html

相关文章:

  • 8.函数定义与使用
  • vue开发环境,生产环境实现跨域请求使用nginx
  • 多IP访问多网段实验
  • Git的原理和使用(四)
  • Redis如何批量删除指定前缀的key
  • 88.【C语言】文件操作(5)
  • php计算经纬度距离 及 某点是否在经纬度节点范围
  • apache flink+starrack+paino 打造流批一体数据仓库
  • 【HeadFirst 设计模式】适配器模式的C++实现
  • XS2123--------IEEE 802.3af 兼容的 PD 和 DC/DC 控制器集成功率 MOSFET V2.0
  • 找不到包的老版本???scikit-learn,numpy,scipy等等!!
  • 【Golang】Go语言web框架Gin响应客户端有哪些方式
  • C++详细笔记(四)
  • 每日OJ题_牛客_集合_排序_C++_Java
  • stable diffusion WEBUI Brief summary
  • 家政小程序搭建,数字化市场发展下的意义
  • RK3588开发笔记-麦克风阵列多pdm通道合并成一个声卡
  • 智能新势力:防爆挂轨巡检机器人助力化工安全
  • 外包干了2个月,技术明显退步
  • Java八股整合(Kafka+RocketMQ+K8S)