可以比较使用google protobuf RPC实现echo service可见。述。

google protobuf仅仅负责消息的打包和解包。并不包括RPC的实现。但其包括了RPC的定义。如果有以下的RPC定义:

service MyService {
rpc Echo(EchoReqMsg) returns(EchoRespMsg)
}

那么要实现这个RPC须要最少做哪些事?总结起来须要完毕下面几步:

client

RPCclient须要实现google::protobuf::RpcChannel。主要实现RpcChannel::CallMethod接口。client调用不论什么一个RPC接口,终于都是调用到CallMethod。这个函数的典型实现就是将RPC调用參数序列化,然后投递给网络模块进行发送。

void CallMethod(const ::google::protobuf::MethodDescriptor* method,
::google::protobuf::RpcController* controller,
const ::google::protobuf::Message* request,
::google::protobuf::Message* response,
::google::protobuf::Closure* done) {
...
DataBufferOutputStream outputStream(...) // 取决于你使用的网络实现
request->SerializeToZeroCopyStream(&outputStream);
_connection->postData(outputStream.getData(), ...
...
}

服务端

服务端首先须要实现RPC接口。直接实现MyService中定义的接口:

class MyServiceImpl : public MyService {
virtual void Echo(::google::protobuf::RpcController* controller,
const EchoReqMsg* request,
EchoRespMsg* response,
::google::protobuf::Closure* done) {
...
done->Run();
}
}

标示service&method

基于以上,能够看出服务端根本不知道client想要调用哪一个RPC接口。

从server接收到网络消息。到调用到MyServiceImpl::Echo还有非常大一段距离。

解决方法就是在网络消息中带上RPC接口标识。

这个标识能够直接带上service name和method name,但这样的实现导致网络消息太大。还有一种实现是基于service name和method name生成一个哈希值,由于接口不会太多,所以较easy找到基本不冲突的字符串哈希算法。

不管哪种方法,server是肯定须要建立RPC接口标识到protobuf service对象的映射的。

这里提供第三种方法:基于option的方法。

protobuf中option机制类似于这样一种机制:service&method被视为一个对象,其有非常多属性,属性包括内置的,以及用户扩展的。用户扩展的就是option。每个属性有一个值。protobuf提供訪问service&method这些属性的接口。

首先扩展service&method的属性。下面定义这些属性的key:

extend google.protobuf.ServiceOptions {
required uint32 global_service_id = 1000;
}
extend google.protobuf.MethodOptions {
required uint32 local_method_id = 1000;
}

应用层定义service&method时能够指定以上key的值:

service MyService
{
option (arpc.global_service_id) = 2302; rpc Echo(EchoReqMsg) returns(EchoRespMsg)
{
option (arpc.local_method_id) = 1;
}
rpc Echo_2(EchoReqMsg) returns(EchoRespMsg)
{
option (arpc.local_method_id) = 2;
}
...
}

以上相当于在整个应用中。每一个service都被赋予了唯一的id,单个service中的method也有唯一的id。

然后能够通过protobuf取出以上属性值:

void CallMethod(const ::google::protobuf::MethodDescriptor* method,
::google::protobuf::RpcController* controller,
const ::google::protobuf::Message* request,
::google::protobuf::Message* response,
::google::protobuf::Closure* done) {
...
google::protobuf::ServiceDescriptor *service = method->service();
uint32_t serviceId = (uint32_t)(service->options().GetExtension(global_service_id));
uint32_t methodId = (uint32_t)(method->options().GetExtension(local_method_id));
...
}

考虑到serviceId methodId的范围,能够直接打包到一个32位整数里:

uint32_t ret = (serviceId << 16) | methodId;

然后就能够把这个值作为网络消息头的一部分发送。

当然server端是须要建立这个标识值到service的映射的:

bool MyRPCServer::registerService(google::protobuf::Service *rpcService) {
const google::protobuf::ServiceDescriptor = rpcService->GetDescriptor();
int methodCnt = pSerDes->method_count(); for (int i = 0; i < methodCnt; i++) {
google::protobuf::MethodDescriptor *pMethodDes = pSerDes->method(i);
uint32_t rpcCode = PacketCodeBuilder()(pMethodDes); // 计算出映射值
_rpcCallMap[rpcCode] = make_pair(rpcService, pMethodDes); // 建立映射
}
return true;
}

服务端收到RPC调用后,取出这个标识值,然后再从_rpcCallMap中取出相应的service和method,最后进行调用:

google::protobuf::Message* response = _pService->GetResponsePrototype(_pMethodDes).New();
// 用于回应的closure
RPCServerClosure *pClosure = new (nothrow) RPCServerClosure(
_channelId, _pConnection, _pReqMsg, pResMsg, _messageCodec, _version);
RPCController *pController = pClosure->GetRpcController();
...
// protobuf 生成的CallMethod,会自己主动调用到Echo接口
_pService->CallMethod(_pMethodDes, pController, _pReqMsg, pResMsg, pClosure);

參考

原文地址: http://codemacro.com/2014/08/31/protobuf-rpc/

written by Kevin Lynx  posted at
http://codemacro.com

版权声明:本文博客原创文章,博客,未经同意,不得转载。

基于protobuf的RPC实现的更多相关文章

  1. RPC框架实现(一) Protobuf的rpc实现

    概述 RPC框架是云端服务基础框架之一,负责云端服务模块之间的项目调用,类似于本地的函数调用一样方便.常见的RPC框架配带的功能有: 编解码协议.比如protobuf.thrift等等. 服务发现.指 ...

  2. 基于HTTP/2和protobuf的RPC框架:GRPC

    谷歌发布的首款基于HTTP/2和protobuf的RPC框架:GRPC Google 刚刚开源了grpc,  一个基于HTTP2 和 Protobuf 的高性能.开源.通用的RPC框架.Protobu ...

  3. 基于Protobuf的分布式高性能RPC框架——Navi-Pbrpc

    基于Protobuf的分布式高性能RPC框架——Navi-Pbrpc 二月 8, 2016 1 简介 Navi-pbrpc框架是一个高性能的远程调用RPC框架,使用netty4技术提供非阻塞.异步.全 ...

  4. 基于Netty打造RPC服务器设计经验谈

    自从在园子里,发表了两篇如何基于Netty构建RPC服务器的文章:谈谈如何使用Netty开发实现高性能的RPC服务器.Netty实现高性能RPC服务器优化篇之消息序列化 之后,收到了很多同行.园友们热 ...

  5. 基于kryonet的RPC,使用kryo进行序列化

    Kryo是一个序列化框架. Kryonet是一个基于kryo的RPC框架,它实现了一套高效简洁的API,它通过NIO实现了TCP和UDP通讯,目前还不支持Http. 自己写了一个测试代码,运行了下,感 ...

  6. github上的golang双向rpc,基于原生“net/rpc”库实现,可以注册回调

    github上的golang双向rpc,基于原生“net/rpc”库实现,可以注册回调.仅支持一个server和一个client交互. 地址:https://github.com/rocket049/ ...

  7. 基于Netty的RPC简易实现

    代码地址如下:http://www.demodashi.com/demo/13448.html 可以给你提供思路 也可以让你学到Netty相关的知识 当然,这只是一种实现方式 需求 看下图,其实这个项 ...

  8. 十七.protobuf在rpc中的使用

    关于protobuf在rpc中的使用,设计到gRPC,相关内容待续....

  9. 这样基于Netty重构RPC框架你不可能知道

    原创申明:本文由公众号[猿灯塔]原创,转载请说明出处标注 今天是猿灯塔“365天原创计划”第5天. 今天呢!灯塔君跟大家讲: 基于Netty重构RPC框架 一.CyclicBarrier方法说明 1. ...

随机推荐

  1. java假设去请求一个网页的数据

    我们能够通过在java程序中模拟浏览器一样,把数据抓下来,详细方法是在java程序中set header和cookie,以下是一个样例: public class NetConnection { pu ...

  2. WPF学习(6)路由事件

    做过.net开发的朋友对于事件应该都不陌生.追溯历史,事件(Event)首先应用在Com和VB上,它是对在MFC中使用的烦琐的消息机制的一个封装,然后.net又继承了这种事件驱动机制,这种事件也叫.n ...

  3. 理解git经常使用命令原理

    git不同于类似SVN这样的版本号管理系统,尽管熟悉经常使用的操作就能够满足大部分需求,但为了在遇到麻烦时不至于靠蛮力去尝试,了解git的原理还是非常有必要. 文件 通过git管理的文件版本号信息所有 ...

  4. RDIFramework.NET ━ .NET高速信息系统开发框架钜献 V2.9 版本震撼发布

    RDIFramework.NET ━ .NET高速信息化系统开发框架钜献 V2.9 版本号震撼公布  全新体验.全新感觉.2015钜献! 继上个版本号"RDIFramework.NET V2 ...

  5. LeetCode 48 Anagrams

    Given an array of strings, return all groups of strings that are anagrams. Note: All inputs will be ...

  6. Android清除缓存功能来实现

    我们都知道在Android的设置->应用程序中能够查看应用程序的相关信息,当中有一个功能是清除缓存. 如图: watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZ ...

  7. Matlab中调用第三方Java代码

    搞了一天,才算搞定. 第一步:定位Matlab中Java环境的ext目录 新建一个M script文件,或者直接在Matlab的交互式命令行中输入: disp(java.lang.System.get ...

  8. zoj 3829 Known Notation(2014在牡丹江区域赛k称号)

    Known Notation Time Limit: 2 Seconds      Memory Limit: 131072 KB Do you know reverse Polish notatio ...

  9. OpenGL模板 Mac Cmake OpenGL(Glut) Template

    自己经常使用的一些功能做一个模板,有灯光效果,你可以用鼠标放大,围绕所述旋转坐标系的原点 watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcHlhbmcxOT ...

  10. zoj 3537 Cake (凸包确定+间隔dp)

    Cake Time Limit: 1 Second      Memory Limit: 32768 KB You want to hold a party. Here's a polygon-sha ...