Protobuf的RPC序列化和调用原理

前面也有一篇文章,当时直接深入到底层的代码了,反而对于这个调用过程不是很熟悉了,所以这里进行讲讲。(有兴趣可以看一下:基于Protobuf的RPC_proto rpc-CSDN博客

对于分布式系统 ,我们需要协调不同系统间的通信机制,因此就有了RPC和Restful api的两个主流的形式。Restful 主要是基于http协议作为一个通信的载体,因此其更多的是面向公共的接口,提供外部服务用的。而RPC则是自己定义的一个方法,然后设计方法参数和返回值的,restful基于http的方法进行访问资源的。

有了restful,为什么要考虑用rpc呢?我们回到使用场景,在分布式内部调用服务的时候,肯定是要保证速度的,所以速度是第一位 的。因此就有了早期的将rpc的消息序列化成二进制的格式进行通过网络进行传输。但是,随着安全性的提升,必须要保证消息的安全性,所以就有了基于http2进行数据传输的grpc,利用了http2的分帧,二进制,头部压缩,流控制的方式进行优化。

前言讲完了,我们这里讲讲最基础的rpc,基于Protobuf的rpc。我们还是直接使用以前的例子,做简单的分析。

复制代码
message ResultCode
{
    int32 errcode = 1; 
    bytes errmsg = 2;
}
message LoginRequest
{
    bytes name = 1;
    bytes pwd = 2;
}
message LoginResponse
{
    ResultCode result = 1;
    bool sucess = 2;
}
message RegisterRequest
{
    uint32 id = 1;
    bytes name = 2;
    bytes pwd = 3;
}
message RegisterResponse
{
    ResultCode result = 1;
    bool sucess = 2;
}
service UserServiceRpc
{
    rpc Login(LoginRequest) returns(LoginResponse);
    rpc Register(RegisterRequest) returns(RegisterResponse);
}

在网络中数据传输,一般有基于像http的/r/n作为一个消息进行传输。而基于二进制的数据怎么传输呢?我们可以通过,message_length(4字节)+message_content(message表示的长度)。message怎么设计呢?因为message内部也有不同的属性,比如ResultCOde:可以设计成一个字节的类型表示int,四个字节表示真实的errcode的真实内容。所以一个ResultCode可以设计成message_length(4字节)+message_content((1字节表示类型+4字节的类型内容)+(1字节类型+1字节类型)....)最后都生成的是二进制的数据。这里类型可能也会进行压缩,比如使用4 bit进行区分等等。

我们这里拓展,讲讲上面的代码,我们看到message是消息的类型。Service则是定义内部分布式调用的服务,rpc Login(LoginRequest) returns(LoginResponse);则是定义了一个方法。所以,这里服务器A提供A服务,服务器B提供B服务。A和B服务可能有很多方法,我们怎么做区分呢?这里就是有一个或者多个的数组,Protobuf里称为描述符的东西,我们直接通过一个Service找到其方法的描述符,同时一个方法的描述符内部也有一个服务的描述符,二者的关系是(一个Service,多个method)。

这里,我们讲一下整体的过程:

1.服务的发起者

复制代码
调用方:Stub
//1MprpeChannel是底层序列化request的地方,以及发送数据的地方
fxbug:UsereveStustuwhnnelO)
//2.rpe方法的请求参数
fixbug:LoginRequest request
request.set_name("zhang san");
requestset_pwd("123456");
//3.rpe方法的响应
fixbug:LoginResponse response,
//4.发起rpc方法的调用同步的rpc调用过程MprpcChannel:callmethod
a
// 4.1 定义rpe的请求header
mprpc:RpcHeader rpcHeader;,
pcHeader.setservicnameservicname);
rpcHeader.setmethodname(methodname);
rpHeadersetarg_size(args_size);
//4.2 序列化rpcheader
uint32 theader size =0;
tstringpheaderst
if(pHeaderSerializeToString(&pheaderst)
{
header_size=pcheader_st.size0:
1
else
{
controller->SetFailed("serializepheadererror!"):
return;
}
4.3序列化所有消息
//组织待发送的rpc请求的字符串
std:string send_rpc_st,
isis
send_xpc_st+=rpc_headet_st://rpcheader
send_xpc_st+=arg_st;//arg
5. 反序列化Response
response->ParseFromArray
  1. 服务的提供者

    1. 服务的发布注册
      RpcProvider::NotifyService(google::protobuf::Service *service)
    2. 请求的解析
      mprpc::RpcHeader rpcHeader;
      std::string service_name;
      std::string method_name;
      uint32_t args_size;
      rpcHeader.ParseFromString(rpc_header_str)
      通过序列化得到的数据,得到对应的方法名,最后找到对应的方法
      3.执行request的回调,返回response
      google::protobuf::Closure done = google::protobuf::NewCallback<RpcProvider,
      const muduo::net::TcpConnectionPtr&,
      google::protobuf::Message
      >(this,&RpcProvider::SendRpcResponse, conn, response);
      调用服务的回调
      service->CallMethod(method, nullptr, request, response, done);
相关推荐
lf132102713 分钟前
用 JSON Schema 管装修节点记录:从照片台账到可校验工程数据
网络·数据库·人工智能·经验分享·物联网·json·智能家居
华清远见成都中心2 小时前
FreeRTOS事件组(Event Group)的工作机制分析
服务器·网络·网络协议
xiaoxiangsiyan2 小时前
RHCE2026云原生路线EX188和EX288完整备考指南
运维·网络·云原生·自动化
西安景驰电子2 小时前
《PTP精确时间协议系列》第二篇:工程部署、调试与性能优化
运维·服务器·网络·数据库·windows·性能优化
tiantianuser3 小时前
NVME-oF IP 设计15 : 适于高速网络存储系统的IP设计1
网络协议·rdma·高速传输·cmac·roce v2
虹科网络安全3 小时前
KnowBe4 SAT 是什么?安全意识培训平台功能与应用详解
网络
艺杯羹4 小时前
古典密码学攻防演进全景:从凯撒移位、频率分析到一次一密与恩尼格玛机破译
网络·人工智能·安全·网络安全·密码学·密码安全
发量惊人的中年网工4 小时前
多品牌酒店门店如何集中管控网络?SD-WAN 实现住客网与业务网隔离的实践
网络·组网
艺术留白5 小时前
MokaTest使用篇-HTTP接口
网络·网络协议·http
金刚钻信息5 小时前
如果服务器坏了,加密文件还能恢复吗?
服务器·网络·加密软件·桌面管理·防泄密