欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 文旅 > 美景 > 【Json-Rpc框架】项目设计——服务模块功能设计

【Json-Rpc框架】项目设计——服务模块功能设计

2025/2/25 7:28:49 来源:https://blog.csdn.net/qq_74276498/article/details/143983569  浏览:    关键词:【Json-Rpc框架】项目设计——服务模块功能设计

【Json-Rpc框架】项目设计——服务模块功能设计

  • 1. 总体服务模块划分
  • 2. 细致模块讲解
    • 2.1 NetWork
    • 2.2 Protocol
    • 2.3 Dispatcher
    • 2.4 RpcRoute
    • 3.5 Publish_Subscrib
    • 3.6 Register_Discovery
    • 3.7 Server

1. 总体服务模块划分

前面我们已经讲过了,整体的项目分为三个功能:

  1. 基于网络通信接收客户端的请求,提供rpc服务
  2. 基于网络通信接收客户端的请求,提供服务注册与发现,服务上线/下线通知
  3. 基于网络通信接收客户端的请求,提供主题操作(创建/删除/注册/取消),消息发布

所以在服务端的模块划分,基于以上理解的功能,可以划分为以下几个模块:

  1. Network:网络通信模块
  2. Protocol:应用层通信协议模块
  3. Dispatcher:消息分发处理模块
  4. RpcRouter:远端调用路由功能模块
  5. Publish-Subscribe:发布订阅功能模块
  6. Registry-Discovery:服务注册/发现/上线/下 线功能模块
  7. Server:基于以上模块整合而出的服务端模块

2. 细致模块讲解

2.1 NetWork

该模块为网络通信模块,实现底层的网络通信功能,这个模块本质上也是⼀个⽐较复杂庞大的模块,因此鉴于项目的庞大,该模块我们将使用陈硕大佬的Muduo库来进行搭建。

2.2 Protocol

应用层存在的意义之一:解析数据,解决数据在传输层,由TCP对数据边界不敏感而可能导致的数据粘包问题,以防止出现取出的数据不一致的问题而所需要的不可缺少的部分。

在前边的muduo库基本使用中,我们能够知道想要让⼀个服务端/客户端对消息处理,就要设置⼀个onMessage的回调函数,在这个函中对收到的数据进行应用层协议处理。Protocol模块就是网络通信协议模块的设计,也就是在网络通信中,我们必须设计⼀个应用层的网络通信协议出来,以解决网络通信中可能存在的粘包问题,而解决粘包有三种方式:特殊字符间隔,定长,LV格式。而我们项目中将使用LV格式来定义应用层的通信协议格式。

  • 如果使用特殊字符的话,一旦我们传输的数据中包含了特殊字符的话就需要进行转义字符处理
  • 而如果使用定长数据传输的话也是不行的,因为客户提交的请求是不定长的,返回的数据也是不定长的,而如果使用定长来传输的话,就需要将定长设置为最大长度的数据,这就会增加网络传输的效率。
  • LV格式分为两部分,一部分是定长的消息长度,另一部分就是边长的消息主体,在树到达传输层的时候先取出头部的定长数据长度字段进行读取,然后通过拿到的长度来读取相应的数据,这样是最要的方法。

而在我们本次项目中,我们LV格式如下:
在这里插入图片描述

Length:该字段固定4字节⻓度,用于表示后续的本条消息数据长度。
MType:该字段为Value中的固定字段,固定4字节长度,用于表示该条消息的类型。
(1. Rpc调用请求/响应类型消息)
(2. 发布/订阅/取消订阅/消息推送类型消息)
(3. 主题创建/删除类型消息)
(4. 服务注册/发现/上线/下线类型消息)
IDLength:为消息中的固定字段,该字段固定4字节⻓度,⽤于描述后续ID字段的实际长度。
MID:在每条消息中都会有⼀个固定字段为ID字段,用于唯⼀标识消息,ID字段⻓度不固定。
Body:消息主题正⽂数据字段,为请求或响应的实际内容字段。

2.3 Dispatcher

模块存在的意义:区分消息类型,根据不同的类型,调用不同的业务处理函数进行消息处理。当muduo库底层通信收到数据后,在onMessage回调函数中对数据进行应用层协议解析,得到⼀条实际消息载荷后,我们就该决定这条消息代表这客户端的什么请求,以及应该如何处理。因此,我们设计出了Dispatcher模块,作为⼀个分发模块,这个模块内部会保存有⼀个hash_map<消息类型,回调函数>,以此由使用者来决定哪条消用哪个业务函数进行处理,当收到消息后,在该模块找到其对应的处理回调函数进行调用即可。

在这里插入图片描述

总体流程就是:服务器启动,有IO事件触发了,收到消息,调用protocol的onMessage进行协议处理,拿到一条消息之后,调用Dispatch的onMessage来进行消息的处理,Dispatcher里面的onMessage就是根据用户注册的映射关系,来决定该消息使用什么样的回调函数来进行处理,进而叫用与之对应的函数。

而消息类型有:

  1. Rpc调用请求/响应类型消息)
  2. 发布/订阅/取消订阅/消息推送类型消息)
  3. 主题创建/删除类型消息)
  4. 服务注册/发现/上线/下线类型消息)

2.4 RpcRoute

RpcRoute模块存在的意义:提供Rpc请求的处理回调函数,分辨客户的请求的服务进行处理得到结果进行返回。本质上RpcRoute的作用其实就是给Dispacher提供处理函数的,内部可以对Rpc请求进行校验。

在处理客户端的业务处理的时候,需要对客户端发起的业务请求进行route,那么客户端就必须提供一个可以让服务器找打对应处理函数的字段描述即:

  • 方法名称
  • 请求对应需要处理参数信息。

在Rpc远端调用中,首先将客户端到服务端的通信链路打通,然后将自己所需要调用的服务名称,以及参数信息传递给服务端,由服务端进行接收处理,并返回结果。然而,不管是客户端要传递给服务端的服务名称以及参数信息,或者服务端返回的结果,都是在上边Protocol中定义的Body字段中,因此Body字段中就存在了另⼀层的正文序列化/反序列化过程。序列化方式有很多种,鉴于当前我们是json-rpc,因此这个序列化过程我们就初步使⽤json序列化来进行,所定义格式如下:

//RPC-request
{"method" : "Add","parameters" : {"num1" : 11,"num2" : 22}
}
//RPC-response
{"rcode" : OK,"result": 33
}
{"rcode" : ERROR_INVALID_PARAMETERS
}

需要注意的是,在服务端,当接收到这么⼀条消息后,Dispatcher模块会找到该Rpc请求类型的回调处理函数进行业务处理,但是在进行业务处理的时候,也是只会将parameters参数字段传入回调函数中进行处理。然而,对服务端来说,应该从入的Json::Value对象中,有什么样的参数,以及参数信息是否符合自己所提供的服务的要求,都应该有⼀个检测,是否符合要求,符合要求了再取出指定字段的数据进行处理。因此,对服务端来说,在进行服务注册的时候,必须有⼀个服务描述,以代码段中的Add请求为例,该服务描述中就应该描述:

  • 服务名称:Add
  • 参数名称:num1,是⼀个整形
  • 参数名称:num2,是⼀个整形
  • 返回值类型:整形

有了这个描述,在回调函数中就可以先对传入的参数进行校验,没问题了则取出指定字段数据进⾏处理并返回结果基于以上理解,在实现该模块时,该有以下设计:

  1. 该模块必须具备⼀个Rpc路由管理,其中包含对于每个服务的参数校验功能
  2. 该模块必须具备⼀个方法名称和方法业务回调的映射
  3. 该模块必须向外提供Rpc请求的业务处理函数。

在这里插入图片描述

总体解释就是:RpcRoute会包括一个hash_map,里面是方法名称与方法描述的映射关系,这个方法描述也是一个结构(ServerDiscribe),这个结构里面包含了方法名称,参数以及格式描述,参数校验接口以及回调函数。同时RpcRoute会对外提供一个onRpcRequest请求,该功能是对于Dispacher数据请求body中的方法名称,从hash_map中找到它的方法描述,然后通过参数校验接口对参数进行校验,如果检验没有则进行回调进行处理请求。

3.5 Publish_Subscrib

Publish_Subscrib存在的意义:针对发布订阅请求进行处理,提供一个回调函数设置给Dispacher模块。
其中发布订阅的操作有以下几个:

  1. 主题创建
  2. 主题删除
  3. 主题订阅
  4. 主题取消订阅
  5. 主题发布消息

在当前的项目中,我们也实现⼀个简单的发布订阅功能,该功能是围绕多个客户端与⼀个服务端来展开的。即,任意⼀个客户端在发布或订阅之前先创建⼀个主题,比如在音乐发布中我们创建⼀个运动音乐主题,哪些客户端希望能够收到运动音乐相关的消息,则就订阅这个主题,服务端会建立起该主题与客户端之间的联系。当某个客户端向服务端发布消息,且发布消息的目标主题是运动音乐主题,则服务端会找出订阅了该主题的客户端,将消息推送给这些客户端。既然涉及到网络通信,那就先将通信消息的正文格式定义出来:

//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. 该模块必须向外提供主题创建/销毁,主题订阅/取消订阅,消息发布处理的业务处理函数

在这里插入图片描述

3.6 Register_Discovery

Register_Discovery存在的意义:就是针对服务注册于发现的请求处理

  • 服务注册/发现类型请求中的细节:
    • 服务注册:服务的提供者告诉中转中心,自己能够提供那些服务
    • 服务发现:服务的请求者询问中转中心,谁能够提供指定的服务
    • 服务上线:在一个提供者上线指定服务后,通知发现过该服务的客户端,有个一个提供者可以提供服务
    • 服务下线:在一个提供者下线后,通知发现过该服务的发现者,该服务已下线。

服务注册模块,该模块主要是为了实现分布式架构而存在的,让每一个rpc请求能够从不同的节点主机上获取自己所需要的服务,让业务更具扩展性,系统更加健壮。而要让rpc-caller直到有哪些rpc-provide能够提供自己所需要的服务,那么就需要有一个注册中心,能够rpc-provide进行注册登记自己的服务,这样rpc-caller就可以通过注册中心发现这些服务。因此,在我们服务端功能中,还需要实现服务的注册/发现,以及服务的上线/下线功能。而是先注册同样需要提供一些可以表示方法的标志性,也就是方法名,同样,rpc-caller知道了方法名也需要知道是哪个服务提供的,而这些都是网络通信范畴的,所以综合上述我们还需要将通信消息的正文格式定义出来:

//Register_Discovery--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. 必须具备一个服务提供者管理
    • 方法与提供者:能够知道谁的那些方法已下线,然后通知发现该服务的客户端。
    • 连接与提供者:当一个服务断开连接的时候,能够通知该提供者提供的服务所对应的发现者,该主机已经下线。
  3. 必须向Dispacher模块提供一个服务注册/发现的业务处理回调函数

这样,当一个rpc-provide进行服务注册,则将其进行管理起来,当rpc-caller进行服务发现那的时候,则将保存的对应服务所对应的主机信息响应给rpc-caller。而当中途有rpc-provide上线登记服务时,则可以给进行了该服务发现的rpc-caller通知,通知rpc-caller当前多了一个对应的rpc-provider。同时当一个rpc-provide下线了,则可以通知发现了该服务的rpc-caller进行服务下线通知。

在这里插入图片描述

3.7 Server

当以上的所有功能模块都完成后,我们就可以将所有功能整合到⼀起来实现服务端程序了。

  • RpcServer:rpc功能模块与网络通信部分结合。
  • RegistryServer:服务发现注册功能模块与网络通信部分结合
  • TopicServer:发布订阅功能模块与网络通信部分结合。
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

热搜词