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);
相关推荐
白晨并不是很能熬夜3 小时前
【RPC】第 4 篇:服务发现 — Zookeeper + 缓存容错
java·后端·程序人生·缓存·zookeeper·rpc·服务发现
信徒_3 小时前
技术选型 RPC 框架
网络·网络协议·rpc
勤劳的进取家3 小时前
应用层基础
运维·网络·学习
计算机安禾3 小时前
【Linux从入门到精通】第37篇:NFS网络文件系统——无状态的数据共享
linux·网络·php
Name_NaN_None3 小时前
Android 手机投屏 iPad :公网+局域网免费方案
网络·计算机外设·电脑·远程工作
2401_873479404 小时前
深度解析IP查询工具与普通IP库的核心区别:选型指南与业务场景对照
网络协议·tcp/ip·php
古城小栈4 小时前
rust 亿级并发模型,实践完成
开发语言·网络·rust
垦利不4 小时前
websocket通信
网络·websocket·网络协议
酣大智4 小时前
POE概念
网络·wifi·无线·poe
byte轻骑兵4 小时前
【HID】规范精讲[7]: 蓝牙HID底层核心——基带与LMP依赖深度解析
网络·人工智能·人机交互·蓝牙·键盘·hid